欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

NodeJS中利用Promise來封裝異步函數(shù)

 更新時間:2015年02月25日 15:11:48   投稿:hebedich  
這篇文章主要介紹了NodeJS中利用Promise來封裝異步函數(shù),使用統(tǒng)一的鏈式API來擺脫多重回調的噩夢,非常的實用的小技能,希望小伙伴們能夠喜歡

 在寫Node.js的過程中,連續(xù)的IO操作可能會導致“金字塔噩夢”,回調函數(shù)的多重嵌套讓代碼變的難以維護,利用CommonJs的Promise來封裝異步函數(shù),使用統(tǒng)一的鏈式API來擺脫多重回調的噩夢。

  Node.js提供的非阻塞IO模型允許我們利用回調函數(shù)的方式處理IO操作,但是當需要連續(xù)的IO操作時,你的回調函數(shù)會多重嵌套,代碼很不美觀,而且不易維護,而且可能會有許多錯誤處理的重復代碼,也就是所謂的“Pyramid of Doom”。

復制代碼 代碼如下:

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});

  這其實就是Node.js的Control flow的問題,對于這個問題,解決方案都許多,比如利用async,或者eventProxy等,不過本文的主題是利用CommonJs規(guī)范中對Promise來解決這個問題。

什么是Promise?

  CommonJs的Promise規(guī)范有許多種,我們一般討論的是Promise/A+規(guī)范,它定義了Promise的基本行為。

  Promise是一個對象,它通常代表一個在未來可能完成的異步操作。這個操作可能成功也可能失敗,所以一個Promise對象一般有3個狀態(tài):Pending,F(xiàn)ulfilled,Rejected。分別代表未完成、成功完成和操作失敗。一旦Promise對象的狀態(tài)從Pending變成Fulfilled或者Rejected任意一個,它的狀態(tài)都沒有辦法再被改變。

  一個Promise對象通常會有一個then方法,這個方法讓我們可以去操作未來可能成功后返回的值或者是失敗的原因。這個then方法是這樣子的:

promise.then(onFulfilled, onRejected)
  顯而易見的是,then方法接受兩個參數(shù),它們通常是兩個函數(shù),一個是用來處理操作成功后的結果的,另一個是用來處理操作失敗后的原因的,這兩個函數(shù)的第一個參數(shù)分別是成功后的結果和失敗的原因。如果傳給then方法的不是一個函數(shù),那么這個參數(shù)會被忽略。

  then方法的返回值是一個Promise對象,這一個特點允許我們鏈式調用then來達到控制流程的效果。這里有許多細節(jié)上的問題,比如值的傳遞或者錯誤處理等。Promise的規(guī)范是這樣定義的:

onFulfilled或者onRejected函數(shù)的返回值不是Promise對象,則該值將會作為下一個then方法中onFulfilled的第一個參數(shù),如果返回值是一個Promise對象,怎么then方法的返回值就是該Promise對象
onFulfilled或者onRejected函數(shù)中如果有異常拋出,則該then方法的返回的Promise對象狀態(tài)轉為Rejected,如果該Promise對象調用then,則Error對象會作為onRejected函數(shù)的第一個參數(shù)
如果Promise狀態(tài)變?yōu)镕ulfilled而在then方法中沒有提供onFulfilled函數(shù),則then方法返回的Promise對象狀態(tài)變?yōu)镕ulfilled且成功的結果為上一個Promise的結果,Rejected同理。
  補充一句,onFulfilled和onRejected都是異步執(zhí)行的。

規(guī)范的實現(xiàn):q

  上面講的是Promise的規(guī)范,而我們需要的是它的實現(xiàn),q是一個對Promise/A+有著較好實現(xiàn)規(guī)范的庫。

  首先我們需要創(chuàng)建一個Promise對象,關于Promise對象創(chuàng)建的規(guī)范在Promise/B中,這里不做詳細的解釋,直接上代碼。

復制代碼 代碼如下:

    function(flag){
        var defer = q.defer();
        fs.readFile("a.txt", function(err, data){
        if(err) defer.reject(err);
            else defer.resolve(data);
            });
            return defer.promise;
    }

  多數(shù)Promise的實現(xiàn)在Promise的創(chuàng)建上大同小異,通過創(chuàng)建一個具有promise屬性的defer對象,如果成功獲取到值則調用defer.resolve(value),如果失敗,則調用defer.reject(reason),最后返回defer的promise屬性即可。這個過程可以理解為調用defer.resolve將Promise的狀態(tài)變成Fulfilled,調用defer.reject將Promise的狀態(tài)變成Rejected。

  在面對一系列連續(xù)的異步方法時,怎么利用Promise寫出漂亮的代碼呢?看下下面的例子。

復制代碼 代碼如下:

    promise0.then(function(result){
        // dosomething
        return result;
    }).then(function(result) {
        // dosomething
        return promise1;   
    }).then(function(result) {
        // dosomething
    }).catch(function(ex) {
        console.log(ex);
    }).finally(function(){
        console.log("final");
    });

  在上面的代碼中,then方法只接受OnFulfilled,而catch方法實際上就是then(null, OnRejected),這樣的話只要一系列異步方法只要始終是成功返回值的,那么代碼就會瀑布式的向下運行,如果其中任意一個異步方法失敗或者發(fā)生異常,那么根據(jù)CommonJs的Promise規(guī)范,將執(zhí)行catch中的function。q還提供了finally方法,從字面上也很好理解,就是不論resolve還是reject,最終都會執(zhí)行finally中的function。

  看上去似乎不錯,代碼更以維護且美觀了,那么如果希望并發(fā)呢?

復制代碼 代碼如下:

     q.all([promise0, promise1, promise2]).spread(function(val0, val1, val2){
                    console.log(arguments);
                }).then(function(){
                    console.log("done");
                }).catch(function(err){
                    console.log(err);
                });

  q也為并發(fā)提供了api,調用all方法并傳遞一個Promise數(shù)組即可繼續(xù)使用then的鏈式風格。還有像q.nfbind等可以將Node.js的原生API轉化成Promise來統(tǒng)一代碼格式也是挺好的。更多api在這里就不一一詳述了。

結論

  本文主要介紹通過使用Promise來解決Node.js控制流問題,但Promise也可同樣應用于前端,EMCAScript6已經(jīng)提供了原生的API支持。需要指出的是Promise并不是唯一的解決方案,async也是一個很好的選擇,并且提供更友好的并發(fā)控制API,不過我覺得Promise在封裝具有異步方法的函數(shù)時更具優(yōu)勢。

好了,本文就先到這里了,希望對大家能夠有所幫助。

相關文章

  • Node.js中的process.nextTick使用實例

    Node.js中的process.nextTick使用實例

    這篇文章主要介紹了Node.js中的process.nextTick使用實例,nextTick函數(shù)有什么用、怎么用、和setTimeout有什么區(qū)別呢,本文就講解了這些知識,需要的朋友可以參考下
    2015-06-06
  • 使用nvm和nrm優(yōu)化node.js工作流的方法

    使用nvm和nrm優(yōu)化node.js工作流的方法

    這篇文章主要介紹了使用nvm和nrm優(yōu)化node.js工作流的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Nodejs 和Session 原理及實戰(zhàn)技巧小結

    Nodejs 和Session 原理及實戰(zhàn)技巧小結

    這篇文章主要介紹了Nodejs 和Session 原理及實戰(zhàn)技巧小結,需要的朋友可以參考下
    2017-08-08
  • koa socket即時通訊的示例代碼

    koa socket即時通訊的示例代碼

    這篇文章主要介紹了koa socket即時通訊的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • Windows 系統(tǒng)下安裝和部署Egret的開發(fā)環(huán)境

    Windows 系統(tǒng)下安裝和部署Egret的開發(fā)環(huán)境

    Egret基于TypeScript開發(fā)的,而TypeScript編譯工具tsc是基于Node.js 開發(fā)的。所以在安裝過程中,我們先需要對于基礎支持工具進行安裝。
    2014-07-07
  • Node快速切換版本、版本回退(降級)、版本更新(升級)

    Node快速切換版本、版本回退(降級)、版本更新(升級)

    這篇文章主要介紹了Node快速切換版本、版本回退(降級)、版本更新(升級),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • nodejs動態(tài)創(chuàng)建二維碼的方法

    nodejs動態(tài)創(chuàng)建二維碼的方法

    這篇文章主要為大家詳細介紹了nodejs動態(tài)創(chuàng)建二維碼的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • express如何使用session與cookie的方法

    express如何使用session與cookie的方法

    本篇文章主要介紹了express如何使用session與cookie的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 基于Node.js的http模塊搭建HTTP服務器

    基于Node.js的http模塊搭建HTTP服務器

    這篇文章主要為大家介紹了基于Node.js的http模塊來搭建HTTP服務器的示例過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-02-02
  • node.js安裝及HbuilderX配置詳解

    node.js安裝及HbuilderX配置詳解

    這篇文章主要介紹了node.js安裝及HbuilderX配置的相關資料,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03

最新評論