1. 程式人生 > >叠代器,生成器(generator)和Promise的“微妙”關系

叠代器,生成器(generator)和Promise的“微妙”關系

執行 data 代碼 表示 是個 mozilla 因此 結構 什麽

需要Promise源碼版的朋友:傳送鏈接

本文主要講述(iterator)和生成器*/yield之間的聯系和各自的用法,以及生成器的高配版本aysnc/await的使用。

大綱:

  • 叠代器(iterator)
  • 生成器 */yield
  • 異步版生成器 aysnc/await

叠代器(iterator)

先瞅瞅“叠代”,這個詞是什麽意思呢?每一次“過程”的重復,稱之為叠代。不過叠代是會保留結果的,也就說每次都是以上一次叠代的結果為基準,開始下一次的叠代。舉個例子,叠代這個詞經常出現在產品開發之中,每個周期都會有產品的叠代開發,但是不可能每次都是從零開始做產品,肯定是基於上一版本的產品進行開發,也就是進行叠代。

從中我們可以整理出關於叠代的兩個關鍵點:

  • 過程是重復的
  • 返回上一次的叠代結果

那麽JS中的“叠代器”是個怎樣的概念呢?

查看MDN中的概念:傳送地址

個人觀點:JS中的叠代器,就是一個數組對象,不斷地調用next重復獲取過程,然後每次都返回一個結果。等到沒有東西可返回了,就終止。因此next的返回對象有兩個屬性donevaluedone表示是否結束了,value表示當前叠代的結果。當donetrue的時候,表示叠代已結束,這時候是沒有返回結果的也就是沒有value這個屬性。

然而叠代器是有一系列的規範的:

查看MDN中的概念:傳送地址

叠代器

  • 關於叠代器,就是我們上面討論的next
    方法,返回donevaluedone: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()

叠代器,生成器(generator)和Promise的“微妙”關系