国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Generator:同步代碼書寫異步情懷

hightopo / 2639人閱讀

摘要:調用方法執行到后暫停,內部環境被保存,執行返回一個對象,為的執行結果,表示迭代器是否完成。當迭代器完成后,為,為的值,繼續執行,將為執行原理回到開頭的例子,給我們提供了直觀的寫法來處理異步回調,它讓代碼邏輯非常清晰。

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

前言:ES6在2015年6月正式發布,它帶給js帶來許多新特性,其中一個就是Generator,雖然其它語言如python早就有了,但js的Generator和它們的還是有點不一樣的,js的Generator重點在解決異步回調金字塔問題,巧妙的使用它可以寫出看起來同步的代碼。

我們都知道js跟其它語言相比,最大的特性就是異步,所以當我們要取異步取一個文件內容時,一般我們會這樣寫

$.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);
    }
}

再取一個C文件可能這樣寫:

$.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);
        }
    }
}

當有更多的異步操作,業務邏輯更為的復雜時,按上面的寫法維護時心中肯定要罵娘了。那有沒有更好一點的寫法呢?在Generator出來之前可以使用promise實現,雖然說promise也是es6的一部分,es6標準未出之前已經有很多ployfill出來了。

$.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的實現要比上面嵌套回調要優雅許多,但也可以一眼看出異步回調的身影。目前js有很多框架要致力解決js金字塔回調,讓異步代碼書寫的邏輯更為清晰,如async, wind.js, promise, deffer。這些框架都有自己的一些約定,如async是以數組形式來寫,promise是以回調參數方式,但它們都不能做到像寫c或java那樣第一行open一個file,然后第二行馬上讀取,來看看最新的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框架包裹,里面一個Generator,從書寫上看它已經和其它同步語言差不多。寫了多年的異步看到上面代碼是不是感覺不可思義呢?這就是Generator帶來的可喜之處,其實es6還更多的新東西等著你發現。下面來了詳細了解一下Generator。

Generator是什么

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

Generator使用function*來定義,內部有yield關鍵字,next方法控制內部執行流程,每執行到一個yield語句就會中斷,并返回一個迭代值,下次執行時從yield的下一個語句繼續執行。一個生成器只能執行一次。

一個簡單的定義如下:

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}

上面代碼通過調用hello(),產生了一個生成器,內部代碼沒有執行。調用next方法執行到yield后暫停,內部環境被保存,next執行返回一個對象,valueyield的執行結果,done表示迭代器是否完成。當迭代器完成后,done為true,value為return的值,繼續執行nextvalue將為undefined

Generator執行原理

回到開頭的例子,Generator給我們提供了直觀的寫法來處理異步回調,它讓代碼邏輯非常清晰。來了解一下Generator內部的一些原理

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

使用chrome工具查看對象內容,可發現里面有nextthrow方法。

當我們執行next方法時,發現其返回了一個對象:

對象含有valuedone兩個字段,value為yield "a"的返回值,即為"a",done表示generator的狀態,為true時表示執行完成。再執行next方法時,可以看到done的值已經為true了,而且value的值為return的值

查看gen自身內部的狀態,可以看到GeneratorStatus已經為closed了

綜上可以得出Generator是通過調用next方法來控制執行流程,當遇到yield語句時暫停執行。next方法返回一個對像{value: "yield", done: false},value存儲的yield 執行結果,done表示迭代器是否執行完成。

通過上面的了解貌似generator并沒有太大卵用,不能如所說的用同步情懷書寫異步代碼。上面漏了很重要的一點就是yield的返回值next的參數。看下面一段代碼:

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

然后過程如下一下:

從上面執行過程可以看到,ret與第二個next的參數值一樣,這是Generator的傳值方式。yield的返回值就是next的參數,第一個next由于執行到yield語句之前就暫停了,所以參數b沒有用。

這里也提一下上面出現的throw方法。

在generator中使用gen.throw("error")來拋出異常。當出現異常后,迭代中止,再次執行gen.next()時,將返回{value: undefined, done: true};

使用try catch可捕獲gen.throw出來的異常。

Generator自動執行封裝

至此對generator了解的也差不多了,但貌似使用它來寫代碼感覺挺變扭的,因為你要不停的next,如果有一個函數能自動執行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);
})

上面提到的Generator內部原理可以總結出,right這邊執行后的結果放到value里,next的參數放到了left這邊。為了讓right這邊執行后的結果放到left,那right就得返回一個function,傳一個callback進行,然后在callback里執行next方法。通過了角Generator的數據傳遞過程就可以寫出一個簡易版的co來自動執行next方法,以達到上面代碼效果:

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);    // 返回讀到的內容
    }
}

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

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就是一個非常簡單的自動執行generator next的函數,且right這邊的值能正確傳到left,唯一的要求是getA的寫法必須trunk的寫法。像我們使用nodejs的一些異步api,可使用trunkify來轉成trunk形式。

在co內部主要靠next來實現循環,靠外部cb()來驅動運行。大體流程如下:

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

支持情況

根據這個ECMAScript 6 compatibility table的資料顯示,目前已經有如下平臺可以支持:

Chrome 35+ (about://flags中開啟)
Firefox 31+ (默認開啟)
nodejs harmony
nodejs 0.11+

參考資料

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

本文首發于有贊技術博客: http://tech.youzan.com/es6-ge...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84319.html

相關文章

  • ES6 Generator異步同步書寫

    摘要:返回值是一個對象,它的第一個屬性是后面表達式的值或者的值第二個屬性表示函數是否執行完成。真正的業務邏輯確實是用同步的方式寫的。 開始前 我們從來沒有停止過對javascript語言異步調用方式的改造,我們一直都想用像java那樣同步的方式去寫異步,盡管Promise可以讓我們將異步回調添加到then方法中,但是這種調用方式仍然不那么優雅,es6 中新增加了generator,我們可以通...

    andycall 評論0 收藏0
  • 2017-07-26 前端日報

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

    Binguner 評論0 收藏0
  • 2017-08-22 前端日報

    摘要:前端日報精選專題之惰性函數中的執行上下文和調用棧是什么個人總結新特性緩存機制詳解技術內幕的秘密中文第期給前端工程師講設計終篇行代碼搭建神經網絡知乎專欄版模塊,桌面支付請求,,以及眾成翻譯你應該知道的知乎專欄技術周刊同步代碼書寫異 2017-08-22 前端日報 精選 JavaScript專題之惰性函數JavaScript 中的執行上下文和調用棧是什么?個人總結(css3新特性) HTT...

    Fundebug 評論0 收藏0
  • 簡單理解Javascript的各種異步流程控制方法

    摘要:所以僅用于簡化理解,快速入門,依然需要閱讀有深入研究的文章來加深對各種異步流程控制的方法的掌握。 原文地址:http://zodiacg.net/2015/08/javascript-async-control-flow/ 隨著ES6標準逐漸成熟,利用Promise和Generator解決回調地獄問題的話題一直很熱門。但是對解決流程控制/回調地獄問題的各種工具認識仍然比較麻煩。最近兩天...

    makeFoxPlay 評論0 收藏0
  • 《Node.js設計模式》基于ES2015+的回調控制流

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

    LiuRhoRamen 評論0 收藏0

發表評論

0條評論

hightopo

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<