for与forEach遇到async

280 阅读1分钟
function transform(a) {
  return new Promise((resolve, reject) => setTimeout(() => resolve(a), 100))
}

async function test(list) {
  for(let i =0, len = list.length; i< len; i++) {
    const item = list[i]
    const data = await transform(item)
    console.log('for-----', Date.now(), data)
  }
}

async function test1(list) {
  list.forEach(async (item) => {
    const data = await transform(item)
    console.log('forEach-------', Date.now(), data)
  })
}

let list = [1,2,3]
list = new Proxy(list, {
  get(target, key) {
    console.log('get-----', key); 
    return target[key]
  }
})
  • 执行for形式(表现为异步,符合预期)
test(list)
  • 执行forEach形式(表现为同步, 不符合预期)
test1(list)

对于forEach在Ecma描述如下

1. Let O be ? ToObject(this value).
2. Let len be ? ToLength(? Get(O, "length")).
3. If IsCallable(callbackfn) is false, throw a TypeError exception.
4. If thisArg is present, let T be thisArg; else let T be undefined.
5. Let k be 0.
6. Repeat, while k < len
    a. Let Pk be ! ToString(k).
    b. Let kPresent be ? HasProperty(O, Pk). 
    c. If kPresent is true, then
        i. Let kValue be ? Get(O, Pk).
        // 直接执行了callbackfn,并没有因为callbackfn是async而暂停
        ii. Perform ? Call(callbackfn, T, « kValue, k, O »).
    d. Increase k by 1.
7. Return undefined.

而for循环中,只有一轮循环结束,才会执行i++,然后判断condition是否成立,成立才能再次进入循环体执行