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
以上就是我要介紹的全部內容了,小夥伴們學習愉快!