iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0
Modern Web

這些那些你可能不知道我不知道的Web技術細節系列 第 13

你可能不知道Array.prototype.forEach()沒跟你說的事情

  • 分享至 

  • xImage
  •  

Array.prototype.forEach()的用法

自知道ArrayforEach的方法後,我自己是還蠻愛用的。

var names = ["World", "Bob", "Alice"]
names.forEach(name => console.log(`Hello, ${name}`))

並且與其他多數Array支援的callback方法一樣,有多個很有效的參數:

var names = ["World", "Bob", "Alice"]
names.forEach((name, idx, arr) => {
    console.log(`Hello, ${name}`)
    arr[idx] += "."
})
console.log(names); // ["World.", "Bob.", "Alice."]

我們甚至可以用而外的thisArg來處理某些事情:

var obj = {
    "World": undefined,
    "Bob": undefined
};

function checkHello(name) {
    if (name in this)
        return void (this[name] = "Yes");
    return void (this[name] = "No");
}

var names = ["World", "Bob", "Alice"];
names.forEach(checkHello, obj);
console.table(obj);

結果:

name result
World Yes
Bob Yes
Alice No

關於性能

在通常情況下,不會由瀏覽器處理大量的資料。通常而言forEach()的需要時間基本沒有什麼差別:

var arr = Array(10).fill("hello")

console.time('for-in')
for(let i in arr) {
  console.log(arr[i])
}
console.timeEnd('for-in')

console.time('forEach')
arr.forEach(e => {
  console.log(e)
})
console.timeEnd('forEach')

下面是我在Google Chrome下簡單測試的結果。

for-in: 2.2939453125 ms
forEach: 1.30517578125 ms

可以認爲差異上僅僅是誤差,無法認爲是for-in還是forEach()比較好。

但還是遇過需要在意性能的時候。在我工作上遇到過資料在瀏覽器處理更爲簡單、方便的情況。而且需要處理的資料量需要到了在意是使用for-in還是forEach()的情況。

實際上,是使用的套件在一次更新後,有大幅度的時間減少。去了解了一下調整方式,才留意到這部分有性能影響。

因為填充後(.fill())的輸出必會需要大量的IO。這裡先證明empty Array在for-inforEach有同樣最終行為(for-of應該可以視與for-in同樣情況)。

var arr = Array(10)

console.time('for-in')
for(let i in arr) {
  console.log('check', arr[i])
}
console.timeEnd('for-in')

console.time('forEach')
arr.forEach(e => {
  console.log('check', e)
})
console.timeEnd('forEach')

可以發現兩種情況都沒有任何輸出,說明兩著都略過了empty的部份。接著就使用非常大的Array試試

var arr = Array(1000000000)//.fill("hello")

console.time('for-in')
for(let i in arr) {
  console.log(arr[i])
}
console.timeEnd('for-in')


console.time('forEach')
arr.forEach(e => {
  console.log(e)
})
console.timeEnd('forEach')

以下是我在 Google Chrome 的測試結果:

for-in: 0.027099609375 ms
forEach: 27090.889892578125 ms

Mozill Firefox Browser的測試結果:

for-in: 0ms - 計時器停止
forEach: 5663ms - 計時器停止

這次就有明顯差距。for-in需要的時間明顯比forEach的時間少。

原因

相比起for-inforEach()是個方法的調用。其次,forEach()接受的callback同樣是一個Function。這意味著每次處理每個內容,都是一次次的函式調用。還記得之前所說的Call Stack嗎?
函式的調用基本都需要函式堆疊分配、函式執行、堆疊回收的過程。

這樣的行為造成相比for-inforEach()需要更多的操作行為。但並不是真的所有函式調用都有這樣的成本,有幾種優化的處理方式,甚至有些是編譯器或直譯器直接的行爲。
(雖然有寫過一篇相關的草稿,不過那並不算是Web技術,主題更接近 Software Development 吧)

本文同時發表於我的隨筆


上一篇
你可能不知道的Call Stack
下一篇
你可能不知道Function的三種用法
系列文
這些那些你可能不知道我不知道的Web技術細節33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言