初遇
生成器函數(shù)参咙,顧名思義龄广,生成對象,生成一個遍歷器蕴侧。
function* generator(){
yield 0;
yield 1;
yield 2;
}
let iterator = generator();
iterator.next(); //{value:0,done:false}
iterator.next(); //{value:1,done:false}
iterator.next(); //{value:2,done:false}
iterator.next(); //{value:undefined,done:true}
-
generator()
為生成器函數(shù)择同,在function
和函數(shù)名
之間添加*
表明該函數(shù)為生成器函數(shù)。 -
generaotor()
調(diào)用返回一個遍歷器净宵,賦值給iterator
敲才。 -
iterator
有多個方法,next()
择葡、return()
紧武、throw()
。 - 通過
yield
和上述三個方法控制生成器函數(shù)代碼塊的執(zhí)行敏储。
yield和next( )
- 生成器代碼不會自動執(zhí)行阻星,多個yield將代碼分成多個部分,等待信號才會執(zhí)行已添,信號就是上述遍歷器的幾個方法妥箕。
- 調(diào)用
next()
時生成器代碼執(zhí)行,執(zhí)行完含yield
語句時停止更舞。下一次調(diào)用next()
時畦幢,繼續(xù)執(zhí)行。 -
next()
的返回值為一個對象:{value:"",done:false
},該對象包含value
疏哗、done
字段呛讲。 -
value
值為本次執(zhí)行代碼中yield
其后表達式的值禾怠。done
的值為true
或者false
返奉,表示當前遍歷器是否執(zhí)行完畢贝搁。 - 上述代碼執(zhí)行情況
1.第一個next()
啟動生成器執(zhí)行,執(zhí)行完yield 0
后停止芽偏,next()
返回值為{value:0,done:false}
雷逆。
2.第二個next()
調(diào)用,生成器繼續(xù)執(zhí)行污尉,執(zhí)行完yield 1
后停止膀哲,next()
返回值為{value:1,done:false}
。
3.第三次next()
調(diào)用和第二次相似被碗,next()
返回值為{value:2,done:false
}
4.第四次next()
調(diào)用時某宪,生成器已執(zhí)行完畢,value
字段值默認值undefined
,done
字段值為true
锐朴。后續(xù)調(diào)用都是如此兴喂。yield語句返回值、next( )參數(shù)
-
yield
語句默認為值為undefined
焚志。
function* generator () { const data0 = yield 0; console.log(data0); //打印出值為undefined const data1 = yield 1; console.log(data1); //打印出值為undefined const data2 = yield 2; console.log(data2); //打印出值為undefined } let iterator = generator(); iterator.next(); iterator.next(); iterator.next(); iterator.next(); //yield語句默認值為undefined衣迷,data0、data1酱酬、data2所賦到的值為undefined
- 通過向
next()
傳入?yún)?shù)改變上個yield
語句的返回值壶谒。
function* generator () { const data0 = yield 1; console.log(data0); //打印出值為"data0" const data1 = yield 1; console.log(data1); //打印出值為"data1" const data2 = yield 2; console.log(data2); //打印出值為"data2" } let iterator = generator(); iterator.next(); iterator.next("data0"); iterator.next("data1"); iterator.next("data2");
-
return( )
這樣一段代碼,生成器中含return
語句膳沽。遍歷器剛好結(jié)束遍歷時汗菜,value
字段默認值為undefined,return
返回的值會賦給當前next()
返回值的value
字段。即代碼塊中第三次next()
調(diào)用挑社。
function* generator(){
yield 0;
yield 1;
return 2;
}
let iterator = generator();
console.log(iterator.next()); //{value:0,done:false}
console.log(iterator.next()); //{value:1,done:false}
console.log(iterator.next()); //{value:2,done:true}
console.log(iterator.next()); //{value:undefined,done:true}
遍歷器的return()
遍歷器的next()
表示繼續(xù)向后執(zhí)行呵俏,return
則表示直接返回,結(jié)束執(zhí)行滔灶。
function* generator() {
yield 0;
yield 1;
yield 2;
}
let iterator = generator();
console.log(iterator.next());
console.log(iterator.return());
- 上述代碼執(zhí)行完
yield 0
后停止普碎,return()
被調(diào)用,提前結(jié)束遍歷录平。后續(xù)yield 1
麻车、yield 2
不會被執(zhí)行。 -
return()
返回值默認為{value:undefined斗这,done:true}
动猬。value
字段值可由return()
的參數(shù)設(shè)置,同next()
表箭。
throw( )
- 所生成遍歷器也有自己的
throw()
赁咙,會優(yōu)先觸發(fā)生成器內(nèi)部的try-catch
。
function* generator() {
try {
const data = yield;
} catch(e) {
console.log("內(nèi)部檢測到",e.message);
}
}
let iterator = generator();
iterator.next();
iterator.throw(new Error("error"))
- 內(nèi)部無
try-catch
時,觸發(fā)外部try-catch
彼水。 - 多次
throw()
時崔拥,第一次由內(nèi)部捕獲,后續(xù)由外部捕獲凤覆。
底層原理
- 基于協(xié)程的實現(xiàn)链瓦。
- 單個線程上可有多個協(xié)程,線程控制權(quán)可交由不同的協(xié)程控制盯桦,每個時間點只能由一個協(xié)程控制慈俯。
- 運行生成器函數(shù)時創(chuàng)建新的協(xié)程,所創(chuàng)建它的協(xié)程的稱為父協(xié)程拥峦。
- 開始時由父協(xié)程控制贴膘,調(diào)用
next()
時,將線程控制權(quán)交由生成器協(xié)程略号,遇到yeild
時將控制權(quán)交回父協(xié)程刑峡。 - 每個協(xié)程在轉(zhuǎn)交控制權(quán)前都會保存自己的調(diào)用棧,方便再次執(zhí)行璃哟。
本文只是浮光掠影氛琢,更多細節(jié)內(nèi)容請前往阮一峰ES6