Generator 函數(shù)是協(xié)程在 ES6 的實(shí)現(xiàn),最大特點(diǎn)就是可以交出函數(shù)的執(zhí)行權(quán)(即暫停執(zhí)行)。
function* gen(x){
var y = yield x+2
return y
}
var g = gen(1)
g.next() //{ value:3,done: false }
g.next() //{ value: undefined, done: true }
由于這個(gè)代碼是可以暫停執(zhí)行的,所以需要在函數(shù)名前面加個(gè)*號(hào)照弥,其他地方跟普通函數(shù)沒啥區(qū)別。
執(zhí)行g(shù)en函數(shù)进副,會(huì)返回一個(gè)對象产喉,對象中有一個(gè)next()函數(shù),調(diào)用這個(gè)函數(shù),會(huì)得到兩個(gè)參數(shù)曾沈,value表示 yield 后面語句的值这嚣,done表示這個(gè)函數(shù)是否執(zhí)行完畢。
我的理解就是:實(shí)際上 yield相當(dāng)于一個(gè)標(biāo)記點(diǎn) 這個(gè)函數(shù)被yield 分成了兩個(gè)階段塞俱,當(dāng)調(diào)用next()的時(shí)候 姐帚,函數(shù)就會(huì)運(yùn)行到標(biāo)記點(diǎn)的位置,并且返回標(biāo)記點(diǎn)第一個(gè)階段的狀態(tài)(yield 后面語句的值障涯,以及是否還有下一個(gè)階段)罐旗。
next 方法返回值的 value 屬性,是 Generator 函數(shù)向外輸出數(shù)據(jù)唯蝶;next 方法還可以接受參數(shù)九秀,這是向 Generator 函數(shù)體內(nèi)輸入數(shù)據(jù)。
function* gen(x){
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }
next() 可以接受一個(gè)參數(shù)粘我,這個(gè)參數(shù)會(huì)被當(dāng)成上一階段的異步任務(wù)的返回結(jié)果被函數(shù)體內(nèi)的變量y接受鼓蜒。所以g.next(2)輸出的value是2。
Generator 函數(shù)內(nèi)部還可以部署錯(cuò)誤處理代碼征字,捕獲函數(shù)體外拋出的錯(cuò)誤都弹。
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1);
g.next();
g.throw('出錯(cuò)了');
// 出錯(cuò)了
上面代碼的最后一行,Generator 函數(shù)體外匙姜,使用指針對象的 throw 方法拋出的錯(cuò)誤畅厢,可以被函數(shù)體內(nèi)的 try ... catch 代碼塊捕獲。
使用 Generator 函數(shù)氮昧,執(zhí)行一個(gè)真實(shí)的異步任務(wù)框杜。
var fetch = require('node-fetch'); //返回一個(gè)Promise對象
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g = gen();
var result = g.next(); //得到的是 fetch(url)(Promise對象)
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});