學(xué)習(xí) Generator 語法,你需要了解function* 、yield、next三個基本概念。
成都創(chuàng)新互聯(lián)公司主要從事成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)榆社,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220function* 用來聲明一個函數(shù)是生成器函數(shù),它比普通的函數(shù)聲明多了一個*,*的位置比較隨意可以挨著 function 關(guān)鍵字,也可以挨著函數(shù)名
yield 產(chǎn)出的意思,這個關(guān)鍵字只能出現(xiàn)在生成器函數(shù)體內(nèi),但是生成器中也可以沒有yield 關(guān)鍵字,函數(shù)遇到 yield 的時(shí)候會暫停,并把 yield 后面的表達(dá)式結(jié)果拋出去
next作用是將代碼的控制權(quán)交還給生成器函數(shù)
// 聲明生成器函數(shù) function* generator() { // A yield 'foo' // B } // 獲取生成器對象 let g = generator(); // 第一個 next(),首次啟動生成器 g.next(); // {value: "foo", done: false} // 喚醒被 yield 暫停的狀態(tài) g.next(); // {value: undefined, done: true}
// 分析一個簡單例子 function* helloGenerator() { yield "hello"; yield "generator"; return; } var h = helloGenerator(); console.log(h.next());//{ value: 'hello', done: false } console.log(h.next());//{ value: 'generator', done: false } console.log(h.next());//{ value: 'undefined', done: true }
創(chuàng)建了h對象,指向helloGenerator的句柄
第一次調(diào)用next(),執(zhí)行到"yield hello",暫緩執(zhí)行,并返回了"hello"
第二次調(diào)用next(),繼續(xù)上一次的執(zhí)行,執(zhí)行到"yield generator",暫緩執(zhí)行,并返回了"generator"。
第三次調(diào)用next(),直接執(zhí)行return,并返回done:true,表明結(jié)束
經(jīng)過上面的分析,yield實(shí)際就是暫緩執(zhí)行的標(biāo)示,每執(zhí)行一次next(),相當(dāng)于指針移動到下一個yield位置
總結(jié)一下 ,Generator函數(shù)是ES6提供的一種異步編程解決方案。通過yield標(biāo)識位和next()方法調(diào)用,實(shí)現(xiàn)函數(shù)的分段執(zhí)行
yield是Generator函數(shù)的暫緩執(zhí)行的標(biāo)識,對于yield只能配合Generator函數(shù)使用,在普通的函數(shù)中使用會報(bào)錯
Generator函數(shù)中還有一種yield*這個表達(dá)方式
function* foo(){ yield "a"; yield "b"; } function* gen(x,y){ yield 1; yield 2; yield* foo(); yield 3; } var g = gen(); console.log(g.next());//{value: 1, done: false} console.log(g.next());//{value: 2, done: false} console.log(g.next());//{value: "a", done: true} console.log(g.next());//{value: "b", done: true} console.log(g.next());//{value: "3", done: true }
當(dāng)執(zhí)行yield*時(shí),實(shí)際是遍歷后面的Generator函數(shù),等價(jià)于下面的寫法:
function* foo(){ yield "a"; yield "b"; } function* gen(x,y){ yield 1; yield 2; for(var value of foo()){ yield value; } yield 3; }
注意:yield 后面只能適配Generator函數(shù)
Generator函數(shù)的暫停執(zhí)行的效果,意味著可以把異步操作寫在yield表達(dá)式里面,等到調(diào)用next方法時(shí)再往后執(zhí)行。這實(shí)際上等同于不需要寫回調(diào)函數(shù)了,因?yàn)楫惒讲僮鞯暮罄m(xù)操作可以放在yield表達(dá)式下面,反正要等到調(diào)用next方法時(shí)再執(zhí)行。所以,Generator函數(shù)的一個重要實(shí)際意義就是用來處理異步操作,改寫回調(diào)函數(shù)
function* loadUI() { showLoadingScreen(); yield loadUIDataAsynchronously(); hideLoadingScreen(); } var loader = loadUI(); // 加載UI loader.next() // 卸載UI loader.next()
上面代碼中,第一次調(diào)用loadUI函數(shù)時(shí),該函數(shù)不會執(zhí)行,僅返回一個遍歷器。下一次對該遍歷器調(diào)用next方法,則會顯示Loading界面,并且異步加載數(shù)據(jù)。等到數(shù)據(jù)加載完成,再一次使用next方法,則會隱藏Loading界面??梢钥吹?,這種寫法的好處是所有Loading界面的邏輯,都被封裝在一個函數(shù),按部就班非常清晰
通過Generator函數(shù)部署Ajax操作,可以用同步的方式表達(dá)。
function* main() { var result = yield request("http://some.url"); var resp = JSON.parse(result); console.log(resp.value); } function request(url) { makeAjaxCall(url, function(response){ it.next(response); }); } var it = main(); it.next();
// 異步函數(shù) function getDataAsync (url) { return new Promise((resolve, reject) => { setTimeout(() => { var res = { url: url, data: Math.random() } resolve(res) }, 1000) }) }