利用promise寫出更加優美的nodejs程序

什麼是promise

promise一個標準,它描述了異步調用的返回結果,包括正確返回結果和錯誤處理。關於詳細的說明文檔能夠參考Promises/A+。目前實現promise標準的模塊有不少,如QbluebirdDeferred,下面咱們以Q爲例,介紹一下promisenodejs中的使用方法。node

###將通常的異步調用的函數轉換爲promise風格的函數 好比通常狀況下,咱們異步讀取文件會寫出下面的代碼:git

fs.readFile("test.txt",function(err,data){
    if(!err){
        console.log(data);
    }else{
        console.error(err);
    }
});

咱們能夠把fs.readFile函數封裝爲promise風格的函數,以下:github

var preadFile = function(file){
    fs.readFile(file,function(err,data){
        var deferred = Q.defer();
        if(!err){
            deferred.resolve(data);
        }else{
            deferred.reject(err);
        }

        return deferred.promise;
    });
}

這樣咱們就能夠這樣調用這個方法了:promise

//then 的第一個參數是正確處理函數,第二個參數是錯誤處理函數
preadFile("test.txt").then(console.log,console.error);

能夠看到這樣調用更加直接明瞭。異步

###使用方法函數

  1. 各個回調函數順序傳遞數據: 在nodejs中咱們回去數據時,時常遇回調函數的返回結果須要傳遞給下一個回調函數,到時很大的回調函數嵌套,promise 能夠很輕鬆的在回調函數之間傳遞參數,看下面的例子:ui

    var fun1 = function (data,cb) {
        cb(null,data+" fun1");
    }
    
    var fun2 = function (data,cb) {
        cb(null,data+" fun2");
    }
    
    var fun3 = function (data,cb) {
        cb(null,data+" fun3");
    }
    
    function main(data,cb){
        fun1(data,function(err,data){
            if(!err){
                fun2(data,function(err,data){
                    if(!err){
                        fun3(data,cb);
                    }else{
                        cb(err);
                    }
                });
            }else{
                cb(err);
            }
        });
    }

能夠看到main函數爲了獲得數據,須要嵌套調用fun1,fun2fun3,若是須要調用不少函數,那麼會造成很大的回調函數嵌套調用,致使代碼看起來很醜陋,並且不容易維護,下面咱們改用promise重寫這段代碼:code

var Q = require("q");
    var fun1 = function (data) {
        var deferred = Q.defer();
        deferred.resolve(data+" fun1");
        return deferred.promise;
    }
    
    var fun2 = function (data) {
        var deferred = Q.defer();
        deferred.resolve(data+" fun2");
        return deferred.promise;
    }
    
    var fun3 = function (data) {
        var deferred = Q.defer();
        deferred.resolve(data+" fun3");
        return deferred.promise;
    }

    function main(data,cb){
       fun1("test")
           .then(fun2)
           .then(fun3)
           .done(function(data){
               cb(null,data);//ok 得到的最終數據爲 --->"test fun1 fun2 fun3"
           },function(err){
               cb(err);//failed
           });
    }
  1. 收集各個回調函數產生的數據:有時候咱們須要執行不少回調函數,然手把這個回調函數的數據一齊傳遞給一個函數處理,此時咱們能夠使用allspread方法,參看以下代碼:文檔

    var Q = require("q");
    var fun1 = function (data) {
        var deferred = Q.defer();
        deferred.resolve(data+" fun1");
        return deferred.promise;
    }
    
    var fun2 = function (data) {
        var deferred = Q.defer();
        deferred.resolve(data+" fun2");
        return deferred.promise;
    }
    
    var fun3 = function (data) {
        var deferred = Q.defer();
        deferred.resolve(data+" fun3");
        return deferred.promise;
    }
    
    Q.all([
        fun2("test1"),fun3("test2"),fun4("test3")
        ]).spread(function(){
            console.log(arguments);//得到的參數爲('test1 fun1', 'test2 fun2', 'test3 fun3' )
        });
  2. 統一處理錯誤:傳統的回調函數方式使用的話,咱們須要在每個回調函數裏判斷是否有錯誤須要處理,這樣會存在不少冗餘代碼,使用promise的話,能夠使用done或者fail統一在一個函數中處理錯誤,如第一個例子同樣,使用done方法的第二個參數處理錯誤。get

相關文章
相關標籤/搜索