成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

Generator:同步代碼書(shū)寫(xiě)異步情懷

hightopo / 2692人閱讀

摘要:調(diào)用方法執(zhí)行到后暫停,內(nèi)部環(huán)境被保存,執(zhí)行返回一個(gè)對(duì)象,為的執(zhí)行結(jié)果,表示迭代器是否完成。當(dāng)?shù)魍瓿珊?,為,為的值,繼續(xù)執(zhí)行,將為執(zhí)行原理回到開(kāi)頭的例子,給我們提供了直觀的寫(xiě)法來(lái)處理異步回調(diào),它讓代碼邏輯非常清晰。

編者按:看完本文,你能對(duì)ES6的Generator有一個(gè)很好的理解,輕松地以同步的方式寫(xiě)異步代碼,也能初步理解到TJ大神的co框架的原理。

前言:ES6在2015年6月正式發(fā)布,它帶給js帶來(lái)許多新特性,其中一個(gè)就是Generator,雖然其它語(yǔ)言如python早就有了,但js的Generator和它們的還是有點(diǎn)不一樣的,js的Generator重點(diǎn)在解決異步回調(diào)金字塔問(wèn)題,巧妙的使用它可以寫(xiě)出看起來(lái)同步的代碼。

我們都知道js跟其它語(yǔ)言相比,最大的特性就是異步,所以當(dāng)我們要取異步取一個(gè)文件內(nèi)容時(shí),一般我們會(huì)這樣寫(xiě)

$.get("http://youzan.com/test.txt", function(data){
    console.log(data);
})

如果取完A文件后又要再取B文件:

$.get("http://youzan.com/A.txt", function(a){
    $.get("http://youzan.com/B.txt", function(b){
        console.log(b);
    }
}

再取一個(gè)C文件可能這樣寫(xiě):

$.get("http://youzan.com/A.txt", function(a){
    $.get("http://youzan.com/B.txt", function(b){
        $.get("http://youzan.com/C.txt", function(c){
            console.log(c);
        }
    }
}

當(dāng)有更多的異步操作,業(yè)務(wù)邏輯更為的復(fù)雜時(shí),按上面的寫(xiě)法維護(hù)時(shí)心中肯定要罵娘了。那有沒(méi)有更好一點(diǎn)的寫(xiě)法呢?在Generator出來(lái)之前可以使用promise實(shí)現(xiàn),雖然說(shuō)promise也是es6的一部分,es6標(biāo)準(zhǔn)未出之前已經(jīng)有很多ployfill出來(lái)了。

$.get("http://youzan.com/A.txt")
    .done(function(a){
        return $.get("http://youzan.com/B.txt");
    })
    .done(function(b){
        return $.get("http://youzan.com/C.txt");
    })
    .done(function(c){
        console.log(c);
    })

promise的實(shí)現(xiàn)要比上面嵌套回調(diào)要優(yōu)雅許多,但也可以一眼看出異步回調(diào)的身影。目前js有很多框架要致力解決js金字塔回調(diào),讓異步代碼書(shū)寫(xiě)的邏輯更為清晰,如async, wind.js, promise, deffer。這些框架都有自己的一些約定,如async是以數(shù)組形式來(lái)寫(xiě),promise是以回調(diào)參數(shù)方式,但它們都不能做到像寫(xiě)c或java那樣第一行open一個(gè)file,然后第二行馬上讀取,來(lái)看看最新的Generator是怎么做的:

co(function* (){
    var a = yield $.get("http://youzan.com/A.txt");
    var b = yield $.get("http://youzan.com/B.txt");
    var c = yield $.get("http://youzan.com/C.txt");
    console.log(c);
})

上面代碼使用了co框架包裹,里面一個(gè)Generator,從書(shū)寫(xiě)上看它已經(jīng)和其它同步語(yǔ)言差不多。寫(xiě)了多年的異步看到上面代碼是不是感覺(jué)不可思義呢?這就是Generator帶來(lái)的可喜之處,其實(shí)es6還更多的新東西等著你發(fā)現(xiàn)。下面來(lái)了詳細(xì)了解一下Generator。

Generator是什么

Generator是生成器的意思,它是一種可以從中退出并在之后重新進(jìn)入的函數(shù)。生成器的環(huán)境(綁定的變量)會(huì)在每次執(zhí)行后被保存,下次進(jìn)入時(shí)可繼續(xù)使用。生成器其實(shí)在其它語(yǔ)言很早就有了,比如python、c#,但與python不同的是js的generator更多的是提供一種異步解決方案。

Generator使用function*來(lái)定義,內(nèi)部有yield關(guān)鍵字,next方法控制內(nèi)部執(zhí)行流程,每執(zhí)行到一個(gè)yield語(yǔ)句就會(huì)中斷,并返回一個(gè)迭代值,下次執(zhí)行時(shí)從yield的下一個(gè)語(yǔ)句繼續(xù)執(zhí)行。一個(gè)生成器只能執(zhí)行一次。

一個(gè)簡(jiǎn)單的定義如下:

function* hello() {
   var a = "b"
   yield "a";
   return a;
}

var gen = hello();
console.log(gen);
// => hello {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: undefined}
console.log(gen.next())
// => {value: "a", done: false}
console.log(gen.next())
// => {value: "b", done: true}

上面代碼通過(guò)調(diào)用hello(),產(chǎn)生了一個(gè)生成器,內(nèi)部代碼沒(méi)有執(zhí)行。調(diào)用next方法執(zhí)行到yield后暫停,內(nèi)部環(huán)境被保存,next執(zhí)行返回一個(gè)對(duì)象,valueyield的執(zhí)行結(jié)果,done表示迭代器是否完成。當(dāng)?shù)魍瓿珊螅?b>done為true,value為return的值,繼續(xù)執(zhí)行nextvalue將為undefined

Generator執(zhí)行原理

回到開(kāi)頭的例子,Generator給我們提供了直觀的寫(xiě)法來(lái)處理異步回調(diào),它讓代碼邏輯非常清晰。來(lái)了解一下Generator內(nèi)部的一些原理

function* hello() {
   yield "a";
   return "b";
}
var gen = hello();
console.log(gen);
// => hello {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: undefined}

使用chrome工具查看對(duì)象內(nèi)容,可發(fā)現(xiàn)里面有nextthrow方法。

當(dāng)我們執(zhí)行next方法時(shí),發(fā)現(xiàn)其返回了一個(gè)對(duì)象:

對(duì)象含有valuedone兩個(gè)字段,value為yield "a"的返回值,即為"a",done表示generator的狀態(tài),為true時(shí)表示執(zhí)行完成。再執(zhí)行next方法時(shí),可以看到done的值已經(jīng)為true了,而且value的值為return的值。

查看gen自身內(nèi)部的狀態(tài),可以看到GeneratorStatus已經(jīng)為closed了

綜上可以得出Generator是通過(guò)調(diào)用next方法來(lái)控制執(zhí)行流程,當(dāng)遇到y(tǒng)ield語(yǔ)句時(shí)暫停執(zhí)行。next方法返回一個(gè)對(duì)像{value: "yield", done: false},value存儲(chǔ)的yield 執(zhí)行結(jié)果,done表示迭代器是否執(zhí)行完成。

通過(guò)上面的了解貌似generator并沒(méi)有太大卵用,不能如所說(shuō)的用同步情懷書(shū)寫(xiě)異步代碼。上面漏了很重要的一點(diǎn)就是yield的返回值next的參數(shù)??聪旅嬉欢未a:

function* hello() {
  var ret = yield "a";
  console.log(ret);
}

然后過(guò)程如下一下:

從上面執(zhí)行過(guò)程可以看到,ret與第二個(gè)next的參數(shù)值一樣,這是Generator的傳值方式。yield的返回值就是next的參數(shù),第一個(gè)next由于執(zhí)行到y(tǒng)ield語(yǔ)句之前就暫停了,所以參數(shù)b沒(méi)有用。

這里也提一下上面出現(xiàn)的throw方法。

在generator中使用gen.throw("error")來(lái)拋出異常。當(dāng)出現(xiàn)異常后,迭代中止,再次執(zhí)行g(shù)en.next()時(shí),將返回{value: undefined, done: true};

使用try catch可捕獲gen.throw出來(lái)的異常。

Generator自動(dòng)執(zhí)行封裝

至此對(duì)generator了解的也差不多了,但貌似使用它來(lái)寫(xiě)代碼感覺(jué)挺變扭的,因?yàn)槟阋煌5膎ext,如果有一個(gè)函數(shù)能自動(dòng)執(zhí)行g(shù)enerator函數(shù)就好了。就像之前提到的代碼:

co(function* (){
    var a = yield $.get("http://youzan.com/A.txt");
    var b = yield $.get("http://youzan.com/B.txt");
    var c = yield $.get("http://youzan.com/C.txt");
    console.log(c);
})

上面提到的Generator內(nèi)部原理可以總結(jié)出,right這邊執(zhí)行后的結(jié)果放到value里,next的參數(shù)放到了left這邊。為了讓right這邊執(zhí)行后的結(jié)果放到left,那right就得返回一個(gè)function,傳一個(gè)callback進(jìn)行,然后在callback里執(zhí)行next方法。通過(guò)了角Generator的數(shù)據(jù)傳遞過(guò)程就可以寫(xiě)出一個(gè)簡(jiǎn)易版的co來(lái)自動(dòng)執(zhí)行next方法,以達(dá)到上面代碼效果:

function co(genFunc) {
  var gen = genFunc();

  var next = function(value){
     var ret = gen.next(value);
     if (!ret.done) {
       ret.value(next);
     }
  }

  next();
}

function getAFromServer(url){
    /*
     *do something sync
     */
    return function(cb) {
       /*
        *do something async
        */ 
       var a = "data A from server";
       cb(a);    // 返回讀到的內(nèi)容
    }
}

function getBFromServer(url){
    /*
     *do something sync
     */
    return function(cb) {
       /*
        *do something async
        */ 
       var b = "data B from server";
       cb(b);    // 返回讀到的內(nèi)容
    }
}

co(function* (){
  var ret = yield getFromSever("url of A");
  console.log(ret);  // 輸出  data A from server
  var retB = yield getFromSever("url of B");
  console.log(retB);  // 輸出  data B from server
})

上面的co就是一個(gè)非常簡(jiǎn)單的自動(dòng)執(zhí)行g(shù)enerator next的函數(shù),且right這邊的值能正確傳到left,唯一的要求是getA的寫(xiě)法必須trunk的寫(xiě)法。像我們使用nodejs的一些異步api,可使用trunkify來(lái)轉(zhuǎn)成trunk形式。

在co內(nèi)部主要靠next來(lái)實(shí)現(xiàn)循環(huán),靠外部cb()來(lái)驅(qū)動(dòng)運(yùn)行。大體流程如下:

了解了co原理,那就可以把它做得更強(qiáng)大一些,如支持Promise,支持nodejs寫(xiě)法的異常處理。這個(gè)可以參考co, trunks的代碼。

支持情況

根據(jù)這個(gè)ECMAScript 6 compatibility table的資料顯示,目前已經(jīng)有如下平臺(tái)可以支持:

Chrome 35+ (about://flags中開(kāi)啟)
Firefox 31+ (默認(rèn)開(kāi)啟)
nodejs harmony
nodejs 0.11+

參考資料

https://developer.mozilla.org...*
http://es6.ruanyifeng.com/#do...
http://kangax.github.io/compa...
http://www.slideshare.net/Ram...

本文首發(fā)于有贊技術(shù)博客: http://tech.youzan.com/es6-ge...

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/84319.html

相關(guān)文章

  • ES6 Generator異步同步書(shū)寫(xiě)

    摘要:返回值是一個(gè)對(duì)象,它的第一個(gè)屬性是后面表達(dá)式的值或者的值第二個(gè)屬性表示函數(shù)是否執(zhí)行完成。真正的業(yè)務(wù)邏輯確實(shí)是用同步的方式寫(xiě)的。 開(kāi)始前 我們從來(lái)沒(méi)有停止過(guò)對(duì)javascript語(yǔ)言異步調(diào)用方式的改造,我們一直都想用像java那樣同步的方式去寫(xiě)異步,盡管Promise可以讓我們將異步回調(diào)添加到then方法中,但是這種調(diào)用方式仍然不那么優(yōu)雅,es6 中新增加了generator,我們可以通...

    andycall 評(píng)論0 收藏0
  • 2017-07-26 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選庖丁解牛二深入解析模板字符串八段代碼徹底掌握高效壓縮文件束的體積譯才不是什么黑魔法呢發(fā)布中文譯數(shù)據(jù)結(jié)構(gòu)棧與隊(duì)列瘋狂的技術(shù)宅中自定義指令修仙之路更好的異步解決方案發(fā)布同步代碼書(shū)寫(xiě)異步情懷有贊前端團(tuán)隊(duì)位運(yùn)算,也許 2017-07-26 前端日?qǐng)?bào) 精選 庖丁解牛React-Redux(二): connect深入解析 ES6:模板字符串_ES6八段代碼徹底掌握Promise高效壓縮...

    Binguner 評(píng)論0 收藏0
  • 2017-08-22 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選專(zhuān)題之惰性函數(shù)中的執(zhí)行上下文和調(diào)用棧是什么個(gè)人總結(jié)新特性緩存機(jī)制詳解技術(shù)內(nèi)幕的秘密中文第期給前端工程師講設(shè)計(jì)終篇行代碼搭建神經(jīng)網(wǎng)絡(luò)知乎專(zhuān)欄版模塊,桌面支付請(qǐng)求,,以及眾成翻譯你應(yīng)該知道的知乎專(zhuān)欄技術(shù)周刊同步代碼書(shū)寫(xiě)異 2017-08-22 前端日?qǐng)?bào) 精選 JavaScript專(zhuān)題之惰性函數(shù)JavaScript 中的執(zhí)行上下文和調(diào)用棧是什么?個(gè)人總結(jié)(css3新特性) HTT...

    Fundebug 評(píng)論0 收藏0
  • 簡(jiǎn)單理解Javascript的各種異步流程控制方法

    摘要:所以?xún)H用于簡(jiǎn)化理解,快速入門(mén),依然需要閱讀有深入研究的文章來(lái)加深對(duì)各種異步流程控制的方法的掌握。 原文地址:http://zodiacg.net/2015/08/javascript-async-control-flow/ 隨著ES6標(biāo)準(zhǔn)逐漸成熟,利用Promise和Generator解決回調(diào)地獄問(wèn)題的話題一直很熱門(mén)。但是對(duì)解決流程控制/回調(diào)地獄問(wèn)題的各種工具認(rèn)識(shí)仍然比較麻煩。最近兩天...

    makeFoxPlay 評(píng)論0 收藏0
  • 《Node.js設(shè)計(jì)模式》基于ES2015+的回調(diào)控制流

    摘要:以下展示它是如何工作的函數(shù)使用構(gòu)造函數(shù)創(chuàng)建一個(gè)新的對(duì)象,并立即將其返回給調(diào)用者。在傳遞給構(gòu)造函數(shù)的函數(shù)中,我們確保傳遞給,這是一個(gè)特殊的回調(diào)函數(shù)。 本系列文章為《Node.js Design Patterns Second Edition》的原文翻譯和讀書(shū)筆記,在GitHub連載更新,同步翻譯版鏈接。 歡迎關(guān)注我的專(zhuān)欄,之后的博文將在專(zhuān)欄同步: Encounter的掘金專(zhuān)欄 知乎專(zhuān)欄...

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

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

0條評(píng)論

hightopo

|高級(jí)講師

TA的文章

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