成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6 異步編程之一:Generator

Eidesen / 2952人閱讀

摘要:生成器是原生提供的異步編程方案,其語(yǔ)法行為和傳統(tǒng)函數(shù)完全不同,阮大的入門(mén)一書(shū)中對(duì)生成器有比較詳盡的介紹,還有一些其他的文章可以參考,比如入門(mén)深入淺出三生成器深入淺出十一生成器,續(xù)篇本文主要是通過(guò)一些代碼示例來(lái)記錄和總結(jié)生成器的用法。

Generator

生成器是es6原生提供的異步編程方案,其語(yǔ)法行為和傳統(tǒng)函數(shù)完全不同,阮大的《ECMAScript 6 入門(mén)》一書(shū)中對(duì)生成器有比較詳盡的介紹,還有一些其他的文章可以參考,比如:

《ECMAScript 6 入門(mén):generator》

深入淺出ES6(三):生成器 Generators

深入淺出ES6(十一):生成器 Generators,續(xù)篇

本文主要是通過(guò)一些代碼示例來(lái)記錄和總結(jié)生成器的用法。

yield 和 next

yieldnext在生成器中扮演著非常重要的角色,前者是一個(gè)操作符,后者是生成器上的一個(gè)函數(shù)。

他們具有以下特性:

需要調(diào)用generator的next函數(shù),生成器中的語(yǔ)句才開(kāi)始執(zhí)行;

next函數(shù)在生成器之外調(diào)用,意味著可以在生成器之外控制其內(nèi)部操作的執(zhí)行過(guò)程;

當(dāng)生成器執(zhí)行到yield操作符就立即執(zhí)行yield之后的語(yǔ)句并暫停,不敢妄言內(nèi)部原理,姑且感性地比作savepoint;

當(dāng)再次調(diào)用生成器的next函數(shù)時(shí),生成器從上次發(fā)生yield"savepoint"繼續(xù)執(zhí)行,直到再次遇到yield,或者遇到是return或者throw生成器就退出;

next的返回值是一個(gè)形如{done:false, value:x}的對(duì)象,每次調(diào)用next都會(huì)使生成器繼續(xù)執(zhí)行,對(duì)于next的返回值有如下規(guī)律:

如果再次遇到yield,next返回值中的value屬性是緊接在這條yield之后的語(yǔ)句執(zhí)行之后的返回值;

如果遇到的是return,那么返回對(duì)象done=truevalue則是return的返回值;

其他情況下,返回對(duì)象{done:false, value:undefined};

next的輸入?yún)?shù)在上一次發(fā)生yield的地方返回,所以第一次調(diào)用next傳入的參數(shù)是“然并卵”,next是在生成器之外調(diào)用的,所以這個(gè)機(jī)制使得我們有能力控制生成器內(nèi)部的行為。

以上說(shuō)了很多,先看一個(gè)用生成器實(shí)現(xiàn)的一個(gè)無(wú)限斐波那契數(shù)列,可以無(wú)限的調(diào)用next函數(shù),他永遠(yuǎn)不會(huì)返回done=true

    const f = function* fibonacci() {
        let [a, b] = [0, 1];
    
        for (;;) {
            yield a;
            [a, b] = [b, a + b];
        }
    }();
    
    //執(zhí)行三次,得到三個(gè)對(duì)象,其value值分別是0,1,1
    for (let i of Array(3).keys()) {
        console.log(f.next());
    }

接下來(lái)通過(guò)一段代碼看看next和yield在傳值和返回值上的情況,如下:

    const iter = function* gen() {
        console.log(`yield ${(yield "a" + 0)}`);
        console.log(`yield ${(yield "b" + 1)}`);
        return "c" + 2;
    }();
    
    console.log(`next:${iter.next(0).value}`);  //輸出 next:a0
    console.log(`next:${iter.next(1).value}`);  //輸出 yield 1 next:b1
    console.log(`next:${iter.next(2).value}`);  //輸出 yield 2 next:c2

對(duì)以上代碼的輸出分析如下:

第一個(gè)next觸發(fā)生成器執(zhí)行到第一個(gè)yield,并立即執(zhí)行"a" + 0 = "a0", a0作為這次next的返回值;

第二個(gè)帶參數(shù)為1next觸發(fā)生成器繼續(xù)執(zhí)行,此時(shí)第一個(gè)yield才返回1,然后執(zhí)行到第二個(gè)yield并立即立即這條yield后面的"b" + 1 = "b1",b1作為這次next的返回;

第三個(gè)next執(zhí)行以此類推……

異步編程方案

在同步編程模型中,每個(gè)函數(shù)總是有序依次地執(zhí)行,一般上一個(gè)函數(shù)執(zhí)行的結(jié)果往往是下一個(gè)函數(shù)的入?yún)?,那么在javascript中如何讓下一個(gè)異步操作等待上一個(gè)異步執(zhí)行得到結(jié)果之后再執(zhí)行呢?

我們現(xiàn)在已經(jīng)有了生成器并且知道next可以觸發(fā)生成器執(zhí)行到yield操作處,而且生成器會(huì)在遇到yield時(shí)立即執(zhí)行后面的語(yǔ)句并暫停,那么如果yield后面是一個(gè)異步操作,而異步操作獲取到結(jié)果之后再調(diào)用next不就實(shí)現(xiàn)了等待的效果么?

    function asyncfuc(v) {
        setTimeout(function() {
            let r = v + 20;
            console.log(r);
            g.next(r); //把異步函數(shù)執(zhí)行得到的結(jié)果傳出并觸發(fā)下一個(gè)yield
        }, 500);
    }
    
    
    let g = function* gen() {
        let v1 = yield asyncfuc(0);
        let v2 = yield asyncfuc(v1);  //上一個(gè)異步調(diào)用的結(jié)果作為下一個(gè)異步調(diào)用的入?yún)?        return v2;
    }();
    
    g.next();
異步操作執(zhí)行鏈

有了前文的基礎(chǔ)我們可以實(shí)現(xiàn)一個(gè)用來(lái)執(zhí)行多個(gè)異步操作的函數(shù),定義一個(gè)run(...functions)方法依次執(zhí)行傳入的函數(shù),如下:

    //這個(gè)方法用來(lái)模擬一個(gè)異步調(diào)用
    function delay(time, func) {
        setTimeout(function() {
            func(`slept for ${time}`);
        }, time);
    }
    
    function run(...functions) {
        //構(gòu)造一個(gè)生成器循環(huán)執(zhí)行傳入的方法
        let generator = function* sync(functions) {
            let result;
            for (var func of functions) {
                result = yield func(result, generator); //前一個(gè)方法執(zhí)行的結(jié)果作為下一個(gè)方法的入?yún)?            }
            return result;
        }(functions);
    
        generator.next(); //觸發(fā)生成器立即執(zhí)行第一個(gè)方法
    }
    
    
    //模擬異步方法調(diào)用, 斐波那契數(shù)列
    function d(result, g) {
        delay(1000, (msg) => {
            let value = result;
            if (value) {
                [value.a, value.b] = [value.b, value.a + value.b];
            } else {
                value = { a: 0, b: 1 };
            }
            console.log(value.a);
            g.next(value);
        });
        return result;
    }
    
    run(d, d, d); //順序執(zhí)行異步方法

以上實(shí)現(xiàn)有個(gè)值得注意的地方是業(yè)務(wù)處理函數(shù)必須帶上一個(gè)生成器作為參數(shù)并在獲得異步結(jié)果之后調(diào)用g.next(value),它影響了業(yè)務(wù)函數(shù)的api,因此具有比較大的侵入性。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86765.html

相關(guān)文章

  • ES6 異步編程之三:Generator續(xù)

    摘要:前言在異步編程之一中實(shí)現(xiàn)了一個(gè)異步函數(shù)調(diào)用鏈,它是一個(gè)順序調(diào)用鏈,很類似責(zé)任鏈模式,但現(xiàn)實(shí)往往不是平鋪直敘的,更多的其實(shí)是峰回路轉(zhuǎn),本文將繼續(xù)討論更多的用法。 前言 在《ES6 異步編程之一:Generator》中實(shí)現(xiàn)了一個(gè)異步函數(shù)調(diào)用鏈,它是一個(gè)順序調(diào)用鏈,很類似責(zé)任鏈模式,但現(xiàn)實(shí)往往不是平鋪直敘的,更多的其實(shí)是峰回路轉(zhuǎn),本文將繼續(xù)討論更多Generator的用法。 作為函數(shù)的Gen...

    JiaXinYi 評(píng)論0 收藏0
  • JavaScript 異步

    摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...

    tuniutech 評(píng)論0 收藏0
  • es6 promise面試

    摘要:執(zhí)行函數(shù)會(huì)返回一個(gè)遍歷器對(duì)象,每一次函數(shù)里面的都相當(dāng)一次遍歷器對(duì)象的方法,并且可以通過(guò)方法傳入自定義的來(lái)改變函數(shù)的行為。函數(shù)可以通過(guò)配合函數(shù)更輕松更優(yōu)雅的實(shí)現(xiàn)異步編程和控制流管理。它和構(gòu)造函數(shù)的不同點(diǎn)類的內(nèi)部定義的所有方法,都是不可枚舉的。 let const的命令 在ES6之前,聲明變量只能用var,var方式聲明變量其實(shí)是很不合理的,準(zhǔn)確的說(shuō),是因?yàn)镋S5里面沒(méi)有塊級(jí)作用域是很不合...

    timger 評(píng)論0 收藏0
  • 談?wù)?em>ES6前后的異步編程

    摘要:回調(diào)函數(shù)這是異步編程最基本的方法。對(duì)象對(duì)象是工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。誕生后,出現(xiàn)了函數(shù),它將異步編程帶入了一個(gè)全新的階段。 更多詳情點(diǎn)擊http://blog.zhangbing.club/Ja... Javascript 語(yǔ)言的執(zhí)行環(huán)境是單線程的,如果沒(méi)有異步編程,根本沒(méi)法用,非卡死不可。 為了解決這個(gè)問(wèn)題,Javascript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種...

    fizz 評(píng)論0 收藏0
  • ES6&ES7中的異步Generator函數(shù)與異步編程

    摘要:傳統(tǒng)的異步方法回調(diào)函數(shù)事件監(jiān)聽(tīng)發(fā)布訂閱之前寫(xiě)過(guò)一篇關(guān)于的文章,里邊寫(xiě)過(guò)關(guān)于異步的一些概念。內(nèi)部函數(shù)就是的回調(diào)函數(shù),函數(shù)首先把函數(shù)的指針指向函數(shù)的下一步方法,如果沒(méi)有,就把函數(shù)傳給函數(shù)屬性,否則直接退出。 Generator函數(shù)與異步編程 因?yàn)閖s是單線程語(yǔ)言,所以需要異步編程的存在,要不效率太低會(huì)卡死。 傳統(tǒng)的異步方法 回調(diào)函數(shù) 事件監(jiān)聽(tīng) 發(fā)布/訂閱 Promise 之前寫(xiě)過(guò)一篇關(guān)...

    venmos 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<