使用 Generator 處理異步調用

Generator 是 ES6 的新規範,它屬於函數的一部分,常用於處理異步代碼,本篇文章將向大家簡單介紹一下 Generator ,如有錯誤,歡迎大家批評指正哈!

1.一個簡單的Generator

這是一個簡單的 Generator 例子:

function* gen() {
    return 'first generator';
}
let generatorResult = gen();

使用 * 表示這是一個Generator函數

我們在控制檯打印一下 generatorResult ,結果是:

console.log(generatorResult)
	
  [object Generator]: {}
	__proto__: Object
  undefined

這說明 generatorResult 不是一個普通的函數,而是一個 Generator 原型的實例,我們需要調用該實例的next方法取值,next 返回的對象中包含了 value 屬性

generatorResult.next()

  [object Object]: {done: true, value: "first generator"}

注意事項:

  • 不能無限制地調用 next 從 Generator 中取值,Generator 如同序列,一旦序列中的值被消費就不能再次消費它
  • 爲了能夠再次消費該序列,需要創建另一個 Generator 實例
generatorResult.next().value  // 第一次取值
  "first generator"  

generatorResult.next()
  [object Object]: {done: true, value: undefined}

generatorResult.next().value  //第二次取值
  undefined

2.yield關鍵字

在 Generator 函數中有一個新的關鍵字,稱爲 yield

一個簡單的 Generator 序列:

function* genSequence() {
    yield 'first';
    yield 'second';
    yield 'third'
}
let generatorSequence = genSequence();

控制檯輸出:

generatorSequence.next()
  [object Object]: {done: false, value: "first"}

generatorSequence.next().value
  "second"

generatorSequence.next().value
  "third"

通過上面的操作我們可以總結出:

  • yield 使 Generator 函數暫停了執行並將結果返回給調用者
  • 調用一次後,yield 將函數置於暫停模式並返回值,而且還準確地記住了暫停的位置
  • 帶有 yield 的 Generator 都會以惰性求值的順序執行(當我們需要時,相應的值纔會被返回)

3.done 屬性

done屬性清楚地告訴我們 Generator 序列的消費情況

generatorSequence.next()
[object Object]: {done: false, value: "first"}

generatorSequence.next().value
"second"

generatorSequence.next().value
"third"

generatorSequence.next().value
undefined

generatorSequence.next()
[object Object]: {done: true, value: undefined}
  • done 爲true 表示 Generator 序列已經完全消費了
  • done 爲false 表示還未消費完

4.向 Generator 傳遞數據

創建一個新的函數和 Generator 實例 :

function* sayName() {
    var firstName = yield;
    var secondName = yield;
    console.log(firstName + secondName)
}
let fullName = sayName();

然後我們在控制檯輸入:

fullName.next()
  [object Object]: {done: false, value: undefined}

fullName.next('chen')
  [object Object]: {done: false, value: undefined}

fullName.next('xiansheng')
  chenxiansheng
  [object Object]: {done: true, value: undefined}

是不是很神奇呢!下面說一下執行過程:

第一次調用 next 時,代碼將返回並暫停於:

var firstName = yield;

由於沒有通過 yield 發送任何值,next 將返回 undefined

第二次調用 next 時, Generator 將從上一次暫停的狀態恢復,即這一行:

var firstName = yield;

由於本次調用 next 時傳入了值 ‘chen’, yield 將被 chen 替換,因此 firstName 的值變爲 chen

賦值後,代碼繼續執行,直到再次遇到 yield 並在此處暫停:

var secondName = yield;

第三次調用 next 時,原理和第二次相同,傳入的 xiansheng 將替換 yield 並賦值於 secondName,接着執行:

console.log(firstName + secondName)

所以控制檯將打印出 chenxiansheng

5.使用 Generator 處理異步調用

看下面的代碼例子:

let generator;
let getDataOne = () => {
    setTimeout(function () {
        // 調用Generator並傳遞數據
        generator.next('dummy data one')
    }, 1000);
}
let getDataTwo = () => {
    setTimeout(function () {
        generator.next('dummy data two')
    }, 1000);
}
function* main() {
    let dataOne = yield getDataOne();
    let dataTwo = yield getDataTwo();
    console.log("data one",dataOne)
    console.log("data two",dataTwo)
}
// 創建一個Generator實例
generator = main();

在控制檯輸入 generator.next() 觸發 main 函數執行,將打印出以下結果:

generator.next()

 [object Object]: {done: false, value: undefined}
 data one dummy data one  // 兩秒後打印出
 data two dummy data two

main 代碼看上去像在同步地調用getDataOne和getDataTwo,但兩個調用是異步進行的

下面簡單說一下整個運行過程:

首先,我們用 generator.next() 調用 main 函數執行,並遇到了第一個 yield :

let dataOne = yield getDataOne();

現在 Generator 進入了暫停模式,但是在暫停之前,它調用了 getDataOne 函數

let getDataOne = () => {
    setTimeout(function () {
        // 調用Generator並傳遞數據
        generator.next('dummy data one')
    }, 1000);
}

因此,當 Generator 暫停時, getDataOne 函數開始執行,這時,時間將會從1000倒數至0,也就是一秒後,將會執行下面這行:

generator.next('dummy data one')

這將會向 yield 語句返回 dummy data one ,因此 dataOne 變量變爲 dummy data one ,一旦 dataOne 被賦值,代碼將會繼續執行到下一行:

let dataTwo = yield getDataTwo();

同理,當這行執行完畢後,我們得到了 dataOne 和 dataTwo :

dataOne = dummy data one
dataTwo = dummy data two

因爲我們在 getDataOne 和 getDataTwo 各設置了1000毫秒後執行,所以控制檯將會在兩秒後同時打印出結果:

 data one dummy data one
 data two dummy data two

以上就是我要介紹的全部內容了,小夥伴們學習愉快!

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