對yield暫緩執行的理解

yield的含義

由於 Generator 函數返回的遍歷器對象,只有調用next方法纔會遍歷下一個內部狀態,所以其實提供了一種可以暫停執行的函數。yield表達式就是暫停標誌。

遍歷器對象的next方法的運行邏輯如下。

(1)遇到yield表達式,就暫停執行後面的操作,並將緊跟在yield後面的那個表達式的值,作爲返回的對象的value屬性值即時返回。

(2)下一次調用next方法時,再繼續往下執行,直到遇到下一個yield表達式。

(3)如果沒有再遇到新的yield表達式,就一直運行到函數結束,直到return語句爲止,並將return語句後面的表達式的值,作爲返回的對象的value屬性值。

(4)如果該函數沒有return語句,則返回的對象的value屬性值爲undefined。

需要注意的是,yield表達式後面的表達式,只有當調用next方法、內部指針指向該語句時纔會執行,因此等於爲 JavaScript 提供了手動的“惰性求值”(Lazy Evaluation)的語法功能。

讓我們看看下面這段代碼

function* f() {
  for(var i = 0; true; i++) {
    var reset = yield i;
    if(reset) { i = -1; }
  }
}

var g = f();

g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next(true) // { value: 0, done: false }

我一開始對他感到茫然,因爲如果每一次for循環都是完整執行的,那麼yield出來的值應該是0,1,2。所以我猜測,for循環被yield攔腰截斷了。以下是我的實踐。

首先,因爲對於var reset來說,它被yield攔腰截斷,所以他應該放在yield的後面

	yield i;
	var reset = next傳進來的值 || undefined;
    if(reset) { i = -1; }

爲了對他們進行驗證,我對上述的代碼進行了下列改動並執行

function* f() {
    for(var i = 0,count = 0; count<=2; i++,count++) {
        var reset = yield i;
        console.log(reset);
        console.log('before'+i);
        if(reset) { i = -1; }
        console.log('after'+i);
    }
}
var g = f();
console.log(g.next())
console.log(g.next()) 
console.log(g.next(true))

如果只執行一次g.next(),即把後面的兩個g.next(),g.next(true)註釋掉
這是返回的結果

{ value: 0, done: false }

如果全部執行,這是返回的結果

{ value: 0, done: false }
undefined
before0
after0
{ value: 1, done: false }
true
before1
after-1
{ value: 0, done: false }

根據結果我們可以知道,第一次的yield確實返回了0,然後yield後面的語句暫緩執行
在這裏插入圖片描述
即我們只執行了紅色框框框住的部分,因爲reset語句不夠完整,所以被放在下一次yield中進行了執行。
在這裏插入圖片描述
在第二次next中,我們先從第一次yield結束之後,把中斷的語句執行了之後執行之後的,直到碰到下一個yield。
第三次next中,我們給next傳入了值,所以reset的值就變成了true,i=-1,i++,把i的值返回出去。這就可以解釋爲什麼yield返回出來的值是0,1,-1了,因爲第一次的for循環只執行了一半就被yield截斷了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章