調(diào)查:
阮一峰先生es6入門里面直接寫 Generator 函數(shù) ,一般人直接就懵了,這是什么?
我查詢了廖雪峰,阮一峰還有開課吧的相關(guān)資料以后,終于得出了一個比較靠譜的結(jié)論:
構(gòu)造器函數(shù)是一種,可以執(zhí)行到一部分就停止的函數(shù),每次調(diào)用,執(zhí)行其中的一部分。由
yield關(guān)鍵字控制每次調(diào)用的部分。
揭秘:
它能夠?qū)崿F(xiàn)一個什么目的呢?就是多個函數(shù)配合協(xié)同作戰(zhàn),第一個函數(shù),執(zhí)行到一半,交給第二個函數(shù),第二個執(zhí)行完了,再轉(zhuǎn)交給第一個函數(shù)繼續(xù)運行。用另一種方式實現(xiàn)了隊列概念。因為一般來說,單線程編程,函數(shù)從上而下執(zhí)行,是不能到一半中斷的,兩個函數(shù)配合就沒法完成了,但是有了構(gòu)造器函數(shù),一種行為變成了可能。
(但是你要注意的是,這個配合,仍然屬于單線程配合,如果想要實現(xiàn)多線程,可以使用worker。單線程協(xié)作,是一種折中的解決方案。)
先看簡單例子: 構(gòu)造器函數(shù)其實非常簡單,再function后面加一個*就行了:
function * fun(){
yield 1+2 //第一次執(zhí)行返回
yield 2+3 //第二次執(zhí)行返回
}
let g=fun()
console.log(g.next()); //{value: 3, done: false}
console.log(g.next()); //{value: 5, done: false}
console.log(g.next()); //{value: undefined, done: true}
由這個例子可以看出來,構(gòu)造器函數(shù)每次都返回一個對象,value是執(zhí)行語句后得到的值,done是執(zhí)行完畢沒有。
傳參:
但是我們最經(jīng)常遇到的情況應(yīng)該是下面這種:
需要把第一部分執(zhí)行完,得到的結(jié)果傳入后面的函數(shù),臥槽。那特么就十分的尷尬了。
請看這個函數(shù),尤其注意a,在函數(shù)的第二句中,a并不代表上面的let a,而是代表傳進來的
function * fun(){
let a=yield 1+2 //第一次執(zhí)行返回
let b=yield 1+3+a //第二次執(zhí)行返回
}
let g=fun();
let g1=g.next();
let g2=g.next(g1.value);
console.log(g1); //{value: 3, done: false}
console.log(g2); //{value: 7, done: false}
延申1:多個函數(shù)協(xié)程
我必須說,真是偉大的構(gòu)造器函數(shù),這一步充滿了想象力。
你必須從這個例子中才能感受到兩個函數(shù)配合的牛逼之處。
通過執(zhí)行到一部分內(nèi)容 突然用yield截斷后返回一個內(nèi)容,然后再通過判斷返回的內(nèi)容
決定用哪個函數(shù)繼續(xù)運行。

let houyi=function*(){
console.log("開始準(zhǔn)備!我是houyi在執(zhí)行");
yield "x"
console.log("進入第四步!我是houyi在執(zhí)行");
yield "s"
}
let xiahou=function*(){
console.log("進入第二步,我是xiahou在執(zhí)行");
yield "h"
console.log("進入第三步!我是xiahou在執(zhí)行");
yield "z"
}
let h=houyi();
let x=xiahou();
//流程控制
function run(gen){
var v = gen.next();
switch(v.value){
// 發(fā)現(xiàn)是x運行x函數(shù)
case "x":
run(x);
break;
// 發(fā)現(xiàn)是h繼續(xù)運行x函數(shù)
case "h":
run(x);
break;
// 發(fā)現(xiàn)是z繼續(xù)運行x函數(shù)
case "z":
run(h);
break;
}
}
//開始執(zhí)行
run(h);
延申2:解決多個異步隊列
// 聲明3個異步函數(shù)
let fun1=()=>{
setTimeout(()=>{
console.log("第一步");
},1000)
}
let fun2=()=>{
setTimeout(()=>{
console.log("第二步");
},800)
}
let fun3=()=>{
setTimeout(()=>{
console.log("第三步");
},600)
}
fun1();
fun2();
fun3();
用構(gòu)造器函數(shù)解決多個異步函數(shù),
理論上異步隊列應(yīng)該用promise方式去處理,構(gòu)造器函數(shù)不是干這個用的,
但是復(fù)雜的情況誰也不好說,這方方式也應(yīng)該熟悉。
// 聲明3個異步函數(shù)
let fun1=(sucess)=>{
setTimeout(()=>{
console.log("第一步");
console.log(sucess);
sucess();
},1000)
}
let fun2=(sucess)=>{
setTimeout(()=>{
console.log("第二步");
sucess();
},800)
}
let fun3=(sucess)=>{
setTimeout(()=>{
console.log("第三步");
sucess();
},600)
}
// 創(chuàng)建順序構(gòu)造器函數(shù)
// 這里主要是利用了構(gòu)造器每次只能執(zhí)行一部分的原理
let shunxu=function*(){
yield fun1;
yield fun2;
yield fun3;
}
// 執(zhí)行函數(shù) 把構(gòu)造器傳進來通過next運行即可
let run=(fn)=>{
const go = fn();
function yunxing(){
const gofun = go.next();
if(gofun.done) return; //.next返回done的值為ture時說明已經(jīng)結(jié)束 此時跳出函數(shù)
// 這里容易讓人費解
// 其實gofun表示的next()對象 它的value是當(dāng)前運行
// 的那個函數(shù),此時再把yunxing函數(shù)傳進入執(zhí)行,其實跟回調(diào)也沒什么區(qū)別了
gofun.value(yunxing)
}
yunxing();
}
run(shunxu);