前方提醒: 篇幅較長,點個贊或者收藏一下,能夠在下一次閱讀時方便查找es6
ES9新增了異步迭代器(Async iterator),異步執行語句(for...await...of)和異步生成器(Async generator),本文帶領你們瞭解這三個新特性,以及如何建立異步迭代器。數組
若是你還不瞭解ES6的
迭代器
,也就是iterator
,先來看看這一部分。數據結構
iterator
是一個特殊的對象,它包含一個next
方法,next
方法返回一個對象,這個對象包含兩個屬性,一個是value
,表示成員的值,一個是done
,done
的值是一個布爾類型
,表示迭代器
是否結束。異步
iterator.next() // 返回 {value: '', done: false}
複製代碼
迭代器
內部會保存一個指針,指向迭代器的成員位置,每調用一次next
方法,指針就會移動到下一個成員,直到指針指向迭代器最後一個成員後面的位置,這時,done
的值爲true
,value
的值通常爲undefined
,須要根據iterator
的實際實現來決定。async
實現一個函數,用來建立
iterator
。函數
幾個關鍵點ui
iterator
是一個對象,而且含有一個next
方法next
方法返回一個對象,包含一個value
屬性和done
屬性,value
表示返回的值,done
是一個布爾類型,表示迭代器是否結束iterator
內部包含一個內部指針,指向迭代器的成員的位置,每調用一次next
方法,指針就會移動到下一個成員,直到指針指向迭代器最後一個成員後面的位置,這時done
的值爲true
// 能夠經過傳入數組或者對象建立iterator
const createIterator = items => {
const keys = Object.keys(items)
const len = keys.length
let pointer = 0
return {
next() {
const done = pointer >= len
const value = !done ? items[keys[pointer++]] : undefined
return {
value,
done
}
}
}
}
複製代碼
const iterator1 = createIterator([1, 2, 3])
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: undefined, done: true }
複製代碼
const iterator2 = createIterator({a: 'a', b: 'b', c: 'c'})
iterator.next() // { value: 'a', done: false }
iterator.next() // { value: 'b', done: false }
iterator.next() // { value: 'c', done: false }
iterator.next() // { value: undefined, done: true }
複製代碼
部署了iterator
接口的數據結構,也就是具備Symbol.iterator
方法的數據結構,就能夠被for...of
遍歷。Symbol.iterator
方法相似於上面實現的createIterator
函數this
iterator
接口const arr = [1, 2, 3]
typeof arr[Symbol.iterator] // 'function'
for (const val of arr) {
console.log(val)
}
// 1
// 2
// 3
複製代碼
iterator
接口,可是咱們能夠本身部署const obj = {a: 'a', b: 'b', c: 'c'}
typeof obj[Symbol.iterator] // 'undefined'
for (const val of obj) {
console.log(val)
}
// TypeError: obj is not iterable
複製代碼
給對象部署iterator
接口spa
const obj = {a: 'a', b: 'b', c: 'c'}
obj[Symbol.iterator] = function() {
const self = this
const keys = Object.keys(self)
const len = keys.length
let pointer = 0
return {
next() {
const done = pointer >= len
const value = !done ? self[keys[pointer++]] : undefined
return {
value,
done
}
}
}
}
for (const val of obj) {
console.log(val)
}
// a
// b
// c
複製代碼
Generator
是一個特殊的函數,函數體內部使用yield
表達式,定義不一樣的內部狀態,當執行Generator
函數時,不會直接執行函數體,而是會返回一個遍歷器對象(iterator)。指針
Generator
函數內部可使用yield
表達式,定義內部狀態function
關鍵字與函數名之間有一個*
function* generator() {
console.log('start');
yield 1
yield 2
yield 3
console.log('end')
}
const iterator = generator() // 這時函數體並無被執行,而是建立了一個iterator
// 當調用iterator的next方法時,函數體開始執行,
iterator.next() // 'start' {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: false}
iterator.next() // 'end' {value: undefined, done: true}
複製代碼
next
方法,函數體會從函數頭部或上次停下來的地方開始執行,直到遇到下一個yield
表達式或者return
語句時中止yield
表達式後面的值會做爲next
方法返回的對象的value
屬性值return
會做爲iterator
結束的標記,而且retur
n的值會做爲next
方法返回的對象的value屬性值改寫一下上面的例子
function* generator() {
yield 1
yield 2
return 3
}
const iterator = generator()
// 當調用iterator的next方法時,函數體開始執行,
iterator.next() // {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: true}
複製代碼
Generator
函數生成的iterator
能夠被for...of
遍歷
function* generator() {
yield 1
yield 2
yield 3
}
const iterator = generator()
typeof iterator[Symbol.iterator] // 'function'
for (const val of iterator) {
console.log(val)
}
// 1
// 2
// 3
複製代碼
在這裏咱們只須要知道Generator
函數會生成一個iterator
就夠了,但實際上Generator
函數遠不止這些,這裏咱們不作詳細介紹了,感興趣的同窗能夠看看阮一峯Generator教程
ES9新增了異步迭代器
異步迭代器
和同步迭代器
相同,都是一個函數,而且含有一個next
方法,區別在於同步迭代器
的next
方法返回一個含有value
和done
屬性的對象,而異步迭代器
的next
方法返回一個Promise
對象,而且Promise
對象的值爲含有value
和done
屬性的對象。
// 這是一個異步迭代器
asyncIterator.next().then(res => {
console.log(res.value, res.done)
})
複製代碼
咱們來實現一個建立異步迭代器
的方法
const createAsyncIterator = items => {
const keys = Object.keys(items)
const len = keys.length
let pointer = 0
return {
next() {
const done = pointer >= len
const value = !done ? items[keys[pointer++]] : undefined
return Promise.resolve({
value,
done
})
}
}
}
複製代碼
和同步迭代器
相同,每調用一次next
方法,異步迭代器
內部的指針就移動到下一個成員
const aynscIterator = createAsyncIterator([1, 2, 3])
aynscIterator.next().then(({value, done}) => {
console.log(value, done) // 1 false
})
aynscIterator.next().then(({value, done}) => {
console.log(value, done) // 2 false
})
aynscIterator.next().then(({value, done}) => {
console.log(value, done) // 3 false
})
aynscIterator.next().then(({value, done}) => {
console.log(value, done) // undefined true
})
複製代碼
for...of
方法可以遍歷具備Symbol.iterator
接口的同步迭代器
數據,可是不能遍歷異步迭代器
。 ES9新增的for...await...of
能夠用來遍歷具備Symbol.asyncIterator
方法的數據結構,也就是異步迭代器
,且會等待前一個成員的狀態改變後纔會遍歷到下一個成員,至關於async
函數內部的await
。
定義一個具備Symbol.asyncIterator
方法的對象
const asyncItems = {
a: 1,
b: 2,
c: 3,
[Symbol.asyncIterator]() {
const items = this
const keys = Object.keys(items)
const len = keys.length
let pointer = 0
return {
next() {
const done = pointer >= len
const value = !done ? items[keys[pointer++]] : undefined;
return new Promise((resolve) => {
setTimeout(() => {
resolve({value, done})
}, 1000)
})
}
}
}
}
複製代碼
使用for...await...of
遍歷該對象
// await只能用在async函數中
async function run() {
for await (const value of asyncItems) {
console.log(value);
}
}
run();
// 1s後打印出 1
// 再過1s後打印出 2
// 再過1s後打印出 3
複製代碼
上面的例子實現了每隔1s打印出對象的屬性值的異步遍歷器接口
,能夠看到, 當使用for...await..of
,遍歷時,會等待前一個Promise
對象的狀態改變後,再遍歷到下一個成員。
咱們能夠採起一種更方便的方式建立異步迭代器
,就是利用異步生成器
。
異步生成器
和普通的生成器很像,可是其是async
函數,內部可使用await
表達式,而且它返回一個具備Symbol.asyncIterator
方法的對象。
定義一個異步生成器
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
複製代碼
使用for...await...of
遍歷該對象
const asyncIterator = asyncGenerator()
typeof asyncIterator[Symbol.asyncIterator] // 'function'
async function run() {
for await (const value of asyncIterator) {
console.log(value);
}
}
run();
// 1
// 2
// 3
複製代碼
異步迭代器
與同步迭代器
相同的是,異步迭代器
也是一個具備next
方法的對象異步迭代器
對象的next
方法返回一個Promise對象
,Promise對象
的值爲一個對象,包含一個value屬性和一個done屬性for...await...of
能夠遍歷具備Symbol.asyncIterator
方法的數據結構,而且會等待上一個成員狀態改變後再繼續執行異步生成器
(Async Generator)能夠用來建立異步迭代器
,它是一個async
類型的generator
函數,內部可使用await
表達式等待異步方法的執行完成,並使用for...await...of
遍歷