前方提醒: 篇幅較長,點個贊或者收藏一下,能夠在下一次閱讀時方便查找es6
ES9新增了異步迭代器(Async iterator),異步執行語句(for...await...of)和異步生成器(Async generator),本文帶領你們瞭解這三個新特性,以及如何建立異步迭代器。數組
若是你還不瞭解ES6的
迭代器
,也就是iterator
,先來看看這一部分。markdown
iterator
是一個特殊的對象,它包含一個next
方法,next
方法返回一個對象,這個對象包含兩個屬性,一個是value
,表示成員的值,一個是done
,done
的值是一個布爾類型
,表示迭代器
是否結束。數據結構
iterator.next() // 返回 {value: '', done: false} 複製代碼
迭代器
內部會保存一個指針,指向迭代器的成員位置,每調用一次next
方法,指針就會移動到下一個成員,直到指針指向迭代器最後一個成員後面的位置,這時,done
的值爲true
,value
的值通常爲undefined
,須要根據iterator
的實際實現來決定。異步
實現一個函數,用來建立
iterator
。async
幾個關鍵點函數
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
函數oop
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
接口this
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)。spa
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
遍歷