Interator迭代器

什么是同步迭代器呢?

舉個例子:

var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  }
}

var iterator = obj[Symbol.iterator]()

iterator.next() // {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: false}
iterator.next() // {value: undefined, done: true}

這里的 iterator 就是同步迭代器了,每調(diào)用一次 next 方法,就返回一個 { value: xx, done: xx } 形式的對象。

什么是異步迭代器呢?

再舉個例子:

var obj = {
  async *[Symbol.asyncIterator]() {
    yield 1;
    yield 2;
    yield 3;
  }
}

var asyncIterator = obj[Symbol.asyncIterator]()

asyncIterator.next().then(data => console.log(data)) // {value: 1, done: false}
asyncIterator.next().then(data => console.log(data)) // {value: 2, done: false}
asyncIterator.next().then(data => console.log(data)) // {value: 3, done: false}
asyncIterator.next().then(data => console.log(data)) // {value: undefined, done: true}

與同步可迭代對象部署了 [Symbol.iterator] 屬性不同的是,異步可迭代對象的標(biāo)志是部署了 [Symbol.asyncIterator] 這個屬性。

這里的 asyncIterator 就是異步迭代器了。與同步迭代器 iterator 不同的是,在 asyncIterator 上調(diào)用 next 方法得到是一個 Promise 對象,其內(nèi)部值是 { value: xx, done: xx } 的形式,類似于 Promise.resolve({ value: xx, done: xx })

為什么會有異步迭代器呢?

同步迭代器里數(shù)據(jù)都是當(dāng)時就能獲取的(沒有延遲),而異步迭代器里的數(shù)據(jù)往往獲取是需要時間的(有延遲)。

下面舉了幾個例子,來說明為什么要用異步迭代器,以及它的使用場景。

  1. 同步迭代器數(shù)據(jù)即用即給,處理順序等于遍歷順序。
var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  }
}

for (let item of obj) {
    console.log(item) // 1 -> 2 -> 3。處理順序等于遍歷順序
}

  1. 如果同步迭代器數(shù)據(jù)獲取需要時間,那么再用 for-of 遍歷的話,就有問題。
var obj = {
  *[Symbol.iterator]() {
    yield new Promise(resolve => setTimeout(() => resolve(1), 5000));
    yield new Promise(resolve => setTimeout(() => resolve(2), 2000));
    yield new Promise(resolve => setTimeout(() => resolve(3), 500));
  }
}

console.log(Date.now())
for (let item of obj) {
    item.then(data => console.log(Date.now(), data))
}

// 1579253648926
// 1579253649427 3 // 1579253649427 - 1579253648926 = 501
// 1579253650927 2 // 1579253650927 - 1579253648926 = 2001
// 1579253653927 1 // 1579253653927 - 1579253648926 = 5001

可以把這里的每個 item 當(dāng)成是接口請求,數(shù)據(jù)返回的時間不一定的。上面的打印結(jié)果就說明了問題所在——我們控制不了數(shù)據(jù)的處理順序。

  1. 再來看看異步迭代器
var obj = {
  async *[Symbol.asyncIterator]() {
    yield new Promise(resolve => setTimeout(() => resolve(1), 5000));
    yield new Promise(resolve => setTimeout(() => resolve(2), 3000));
    yield new Promise(resolve => setTimeout(() => resolve(3), 500));
  }
}

console.log(Date.now())
for await (let item of obj) {
    console.log(Date.now(), item)
}

// 1579256590699
// 1579256595700 1 // 1579256595700 - 1579256590699 = 5001
// 1579256598702 2 // 1579256598702 - 1579256590699 = 8003
// 1579256599203 3 // 1579256599203 - 1579256590699 = 8504

注意,異步迭代器要聲明在 [Symbol.asyncIterator] 屬性里,使用 for-await-of 循環(huán)處理的。最終效果是,對任務(wù)挨個處理,上一個任務(wù)等待處理完畢后,再進(jìn)入下一個任務(wù)。

因此,異步迭代器就是用來處理這種不能即時拿到數(shù)據(jù)的情況,還能保證最終的處理順序等于遍歷順序,不過需要依次排隊等待。

for-await-of

for-await-of 除了能用在異步可迭代對象上,還能用在同步可迭代對象上。

var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  }
}

for await(let item of obj) {
    console.log(item) // 1 -> 2 -> 3
}

是這樣的,如果 for-await-of 發(fā)現(xiàn)遍歷對象上沒有 [Symbol.asyncIterator] 的話,就去調(diào)用 [Symbol.iterator]。我們都知道,由此得來的是同步迭代器,在這個迭代器上調(diào)用 next 方法的時候,返回就是一個普通的對象,結(jié)構(gòu)類似于 { value: xx, done: xx }。

await obj 的結(jié)果還是 obj,下例為證:

(async function() {
    var obj = { value: 1, done: false }
    console.log((await obj) === obj) // true
})()

所以才會有上面的結(jié)果。

還有一點,需要注意的是,如果一個對象上同時部署了 [Symbol.asyncIterator][Symbol.iterator],那就會優(yōu)先使用 [Symbol.asyncIterator] 生成的異步迭代器。這很好理解,因為 for-await-of 本來就是為異步迭代器而生的。

var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  },
  async *[Symbol.asyncIterator]() {
    yield 4;
    yield 5;
    yield 6;
  }
}

for await(let item of obj) {
    console.log(item) // 4 -> 5 -> 6。優(yōu)先使用由 [Symbol.asyncIterator] 生成的異步迭代器
}

鏈接:https://juejin.im/post/6844904051390283790

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容