須要Promise源碼版的朋友:傳送連接html
本文主要講述(iterator)和生成器*/yield
之間的聯繫和各自的用法,以及生成器的高配版本aysnc/await
的使用。數組
大綱:promise
- 迭代器(iterator)
- 生成器
*/yield
- 異步版生成器
aysnc/await
迭代器(iterator)
先瞅瞅「迭代」,這個詞是什麼意思呢?每一次「過程」的重複,稱之爲迭代。不過迭代是會保留結果的,也就說每次都是以上一次迭代的結果爲基準,開始下一次的迭代。舉個例子,迭代這個詞常常出如今產品開發之中,每一個週期都會有產品的迭代開發,可是不可能每次都是從零開始作產品,確定是基於上一版本的產品進行開發,也就是進行迭代。異步
從中咱們能夠整理出關於迭代的兩個關鍵點:async
- 過程是重複的
- 返回上一次的迭代結果
那麼JS中的「迭代器」是個怎樣的概念呢?this
查看MDN中的概念:傳送地址url
我的觀點:JS中的迭代器,就是一個數組對象,不斷地調用
next
重複獲取過程,而後每次都返回一個結果。等到沒有東西可返回了,就終止。所以next
的返回對象有兩個屬性done
和value
。done
表示是否結束了,value
表示當前迭代的結果。當done
爲true
的時候,表示迭代已結束,這時候是沒有返回結果的也就是沒有value
這個屬性。spa
然而迭代器是有一系列的規範的:.net
查看MDN中的概念:傳送地址code
迭代器
- 關於迭代器,就是咱們上面討論的
next
方法,返回done
和value
(done:true
時能夠省略)兩個參數。
function iteratorFunc(){ let arr=[...arguments] let nIndex=0 return { next:()=>{ return nIndex<arr.length? {value:arr[nIndex++],done:false}:{done:true} } } } let a=iteratorFunc(1,2,3) console.log(a.next())//{done:false,value:1} console.log(a.next())//{done:false,value:2} console.log(a.next())//{done:false,value:3} console.log(a.next())//{done:true}
可迭代「對象」
- 關於可迭代「對象」,咱們須要再對象上實現
@@iterator
方法,也就是[Symbol.iterator]
,返回一個自定義的迭代方法,以代表這個對象是能夠迭代的。有些JS內置的對象就是可迭代的,好比String,Array。
自帶的可迭代事例:
let str="我是歡樂的迭代器" let b=str[Symbol.iterator]() console.log(b.next())//{value: "我", done: false} console.log(b.next())//{value: "是", done: false} console.log(b.next())//{value: "歡", done: false}
有沒有很神奇啊!用了這麼久的字符串,竟然還有這種操做。他的效果等同於上方的自定義迭代方法。那麼咱們來寫個自定義的迭代方法:
str[Symbol.iterator] = function() { return { // this is the iterator object, returning a single element, the string "bye" next: function() { this._index += 2 if (this._index<str.length) { return { value: str[this._index], done: false }; } else { return { done: true }; } }, _index:-2 }; }; let c=str[Symbol.iterator]() console.log(c.next())//{value: "我", done: false} console.log(c.next())//{value: "歡", done: false} console.log(c.next())//{value: "的", done: false} console.log(c.next())//{value: "代", done: false} console.log(c.next())//{done: true}
這裏我寫的迭代器是返回一個隔一個字符。運行成功~yeah~
生成器(generator)
感受寫迭代器仍是很繞呢,因而出現了生成器(generator),專門幫咱們生成迭代器的存在。
function * g(){} let it= g() console.log(it.next())//{value: undefined, done: true}
看到熟悉的結構沒有!{value: undefined, done: true}
,不過咱們沒有值。這個時候要向你們推薦*
的好基友yield
,一個yield
對應一個next
的值。
咱們改寫下上方的字符串的迭代器:
str[Symbol.iterator]= function * (){ let index=-2; while(index<this.length){ index += 2 yield this[index] } } let kk=str[Symbol.iterator]() console.log(kk.next())//{value: "我", done: false} console.log(kk.next())//{value: "歡", done: false} console.log(kk.next())//{value: "的", done: false} console.log(kk.next())//{value: "代", done: false}
是否是方便了不少。
咱們帶着幾個疑問來看看生成器:
yield
的返回值是啥?- 執行順序?
實例代碼:
function * gy(){ console.log("zero") let fisrt=yield "first" console.log("fisrt",fisrt) let second=yield "first" console.log("second",second) } let ity= gy()
第一次執行ity.next()
,只打印了zero
第二次執行ity.next()
,只打印了first undefined
第三次執行ity.next("third")
,只打印了second third
因而可知每次的next都止步於yield
,就再也不執行下去了。yield
每次返回的都是當前ity.next(value)
的value
值。
aysnc/await
咱們來看看對於Promise這個對象的迭代器,咱們該怎麼處理。也就是每一個迭代器都是異步的。
function setTime(value,id){ return new Promise((r,j)=>setTimeout(() => { console.log(value) r(id) }, 10)) } function *a(){ let r1 = yield setTime("first",1) console.log(r1) let r2 =yield setTime("second",2) console.log(r2) let r3 =yield setTime("third",3) console.log(r3) } let k=a(); new Promise((resolve,reject)=>{ function next(data){ let {value,done}=k.next(data) //k.next()返回一個promise,所以能夠then if(!done){ value.then((data)=>{ console.log(data) next(data) }) } } next(); })
由於每一個都是異步的,因此須要咱們二次處理,這個時候aysnc/await
就能夠出場了。只須要把*/yield無縫改爲aysnc/await便可。
async function a() { let r1 = await setTime("first",1) console.log(r1) let r2 = await setTime("second",2) console.log(r2) let r3 = await setTime("third",3) console.log(r3) } a()