1.簡單知識點(diǎn)
執(zhí)行 Generator 函數(shù)會返回一個遍歷器對象
每次調(diào)用next方法毡庆,內(nèi)部指針就從函數(shù)頭部或上一次停下來的地方開始執(zhí)行,直到遇到下一個yield表達(dá)式(或return語句)為止随橘。換言之,Generator 函數(shù)是分段執(zhí)行的,yield表達(dá)式是暫停執(zhí)行的標(biāo)記对嚼,而next方法可以恢復(fù)執(zhí)行。
yield表達(dá)式只能用在 Generator 函數(shù)里面绳慎,用在其他地方都會報錯纵竖。
yield表達(dá)式如果用在另一個表達(dá)式之中,必須放在圓括號里面杏愤。
-
對象的Symbol.iterator方法即是對象的便利生成器函數(shù)靡砌。Generator生成的遍歷生成器對象也具有Symbol.iterator屬性,這個屬性返回他本身珊楼。
function* gen(){ // some code } var g = gen(); g[Symbol.iterator]() === g//true
2.next()
-
yield表達(dá)式本身無返回值通殃。next()可以帶一個參數(shù),當(dāng)作上一個yield的返回值厕宗。
e.g.function * fibonacci(){ let [prev, curr] = [0, 1]; for(;;){ [prev, curr] = [curr, curr+prev]; yield curr; } } for(let n of fibonacci()){ if(n>1000){ break; } console.log(n); }
補(bǔ)充:for..of画舌,解構(gòu)賦值,Array.from()媳瞪,...擴(kuò)展運(yùn)算符調(diào)用的都是遍歷器接口骗炉。
3.throw()
throw拋出的錯誤,由try-catch語句中的catch捕獲蛇受。throw 分為外部的throw命令和生成器的throw()方法句葵。throw命令拋出的錯誤只能被函數(shù)體外捕獲。
-
函數(shù)體外拋出異常,函數(shù)能夠捕獲乍丈。
try{ g.throw("error"); }catch(e){ console.log(e); }
一旦 Generator 執(zhí)行過程中拋出錯誤剂碴,且沒有被內(nèi)部捕獲,就不會再執(zhí)行下去了轻专。如果此后還調(diào)用next方法忆矛,將返回一個value屬性等于undefined、done屬性等于true的對象请垛,即 JavaScript 引擎認(rèn)為這個 Generator 已經(jīng)運(yùn)行結(jié)束了催训。
同樣函數(shù)內(nèi)部拋出的錯誤,函數(shù)外部可以捕獲宗收。函數(shù)內(nèi)部有try-catch語句塊漫拭,g.throw()先被函數(shù)內(nèi)部的try-catch捕獲。當(dāng)函數(shù)內(nèi)部不存在try-catch語句塊時混稽,直接被函數(shù)外部的try-catch捕獲采驻。捕獲到函數(shù)內(nèi)部拋出的錯誤錯誤,則g.next().done為true匈勋,表示遍歷結(jié)束礼旅,不再執(zhí)行。
- throw方法被捕獲后洽洁,會附帶執(zhí)行下一條yield表達(dá)式痘系。
- throw命令與g.throw()無關(guān)。兩者不影響诡挂。throw命令不會影響遍歷器的狀態(tài)碎浇。
4.return()
g.return('foo');
調(diào)用return()結(jié)束遍歷器,并返回遍歷器的返回值璃俗。
注意try-finally語句塊奴璃。調(diào)用return()后,執(zhí)行finally塊中的代碼城豁,執(zhí)行完后返回return()苟穆。
總結(jié):return(),next()唱星,throw()雳旅,都是對yield表達(dá)式的替換。next是值的替換间聊,throw()替換成throw語句攒盈,return()替換成return語句
5.關(guān)于yield
在generator函數(shù)中調(diào)用generator。利用yield*
yield * iterator對象 相當(dāng)于for...of遍歷的簡寫-
利用yield創(chuàng)建二叉樹
function Tree(left, label, right) { this.left = left; this.label = label; this.right = right; } function make(array) { // 判斷是否為葉節(jié)點(diǎn) if (array.length == 1) return new Tree(null, array[0], null); return new Tree(make(array[0]), array[1], make(array[2])); } let tree = make([[['a'], 'b', ['c']], 'd', [['e'], 'f', ['g']]]); console.log(tree);
利用yield遍歷二叉樹
6.generator中的this
generator不能夠和new一起用哎榴,所以就不能夠?qū)his綁定在生成器
出現(xiàn)的問題是:
function* g() {
this.a = 11;
}
let obj = g();
obj.a // undefined
解決方法型豁,創(chuàng)建空對象僵蛛,使用call綁定generator內(nèi)部的this對象
function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
var obj = {};
var f = F.call(obj);
f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}
obj.a // 1
obj.b // 2
obj.c // 3
7.generator函數(shù)與狀態(tài)機(jī)
generator中一個yield就是一個狀態(tài)
*8.generator與協(xié)程序
- 協(xié)程就是:一個線程(或函數(shù))執(zhí)行到一半,可以暫停執(zhí)行迎变,將執(zhí)行權(quán)交給另一個線程(或函數(shù))充尉,等到稍后收回執(zhí)行權(quán)的時候,再恢復(fù)執(zhí)行衣形。這種可以并行執(zhí)行驼侠、交換執(zhí)行權(quán)的線程(或函數(shù)),就稱為協(xié)程谆吴。
- 協(xié)程與普通線程的區(qū)別:同一時間可以有多個線程處于運(yùn)行狀態(tài)倒源,但是運(yùn)行的協(xié)程只能有一個,其他協(xié)程都處于暫停狀態(tài)纪铺。此外相速,普通的線程是搶先式的,到底哪個線程優(yōu)先得到資源鲜锚,必須由運(yùn)行環(huán)境決定,但是協(xié)程是合作式的苫拍,執(zhí)行權(quán)由協(xié)程自己分配芜繁。
9.generator的應(yīng)用
異步同步化
利用yield,按順序執(zhí)行異步函數(shù)
多步驟管理
-
promise的方式
Promise.resolve(step1) .then(step2) .then(step3) .then(step4) .then(function (value4) { // Do something with value4 }, function (error) { // Handle any error from step1 through step4 }) .done();
promise.done:不會反悔promise對象绒极,因此不能夠接cache()骏令,形成promise鏈。異常直接拋出給外部垄提。作用榔袋,防止promise中的人為的,難以查找出的錯誤铡俐。
-
generator 中yield
function* longRunningTask(value1) { try { var value2 = yield step1(value1); var value3 = yield step2(value2); var value4 = yield step3(value3); var value5 = yield step4(value4); // Do something with value4 } catch (e) { // Handle any error from step1 through step4 } }
注意:這里generator是同步化的凰兑,不存在異步調(diào)用。
部署iterator 接口
function* iterEntries(obj) {
let keys = Object.keys(obj);
for (let i=0; i < keys.length; i++) {
let key = keys[i];
yield [key, obj[key]];
}
}
let myObj = { foo: 3, bar: 7 };
for (let [key, value] of iterEntries(myObj)) {
console.log(key, value);
}
// foo 3
// bar 7
Object.keys()
Object.keys() 方法會返回一個由一個給定對象的自身可枚舉屬性組成的數(shù)組审丘,數(shù)組中屬性名的排列順序和使用 for...in循環(huán)遍歷該對象時返回的順序一致 (兩者的主要區(qū)別是 一個 for-in 循環(huán)還會枚舉其原型鏈上的屬性)
作為數(shù)據(jù)結(jié)構(gòu)