首頁  >  文章  >  web前端  >  node.js下when.js 的非同步程式設計實作_node.js

node.js下when.js 的非同步程式設計實作_node.js

WBOY
WBOY原創
2016-05-16 16:29:191498瀏覽

假設一個商業場景:

透過rss地址,取得rss並儲存於文件,rss地址保存於文件中。

完成該場景的業務需要完成3個任務:

1.從檔案讀取rss位址。

2.取得rss。

3.儲存於文件。

最後將這三個任務整合。

準備:

存放rss地址的文件,address.txt。

http://programmer.csdn.net/rss_programmer.html
 
任務1:

讀取rss位址檔案的內容並透過callback回傳。

複製程式碼 程式碼如下:

var getRssAddress = function(path, callback) {
  fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
    callback(err, data);
  });
}

任務2:

 透過rss位址get到rss,並透過callback回傳錯誤或資料。

複製程式碼 程式碼如下:

var getRss = function(url, callback) {
  var data = '';
  http.get(url, function(res) {
    res.on('data', function(chrunk) {
      data = chrunk;
    });
    res.on('end', function() {
      callback(null, data);
    });
  }).on('error', function(err) {
    callback(err, null);
  });
}

 

任務3:

將rss儲存於檔案並透過callback回傳錯誤。

複製程式碼 程式碼如下:

var saveRss = function(data, callback) {
  fs.writeFile('rss.txt', data, 'utf8', function(err) {
    callback(err);
  });
}

整合:

複製程式碼 程式碼如下:

getRssAddress('address.txt', function(err, data) {
  if(err) {
    console.log(err);
    return;
  }
  getRss(data, function(err, data) {
    if(err) {
      console.log(err);
      return;
    }
    saveRss(data, function(err) {
      if(err) console.log(err);
    });
  });
});

上面的程式碼是全非同步處理,使用最常見的callback處理非同步邏輯的返回,好處是標準寫法,大家都能容易接受;壞處是耦合性太強,處理異常麻煩,程式碼不直觀,特別是處理業務邏輯複雜和處理任務多的場景,層層的callback會讓人眼冒金星,程式碼難以維護。

Promise/A規範的實作之一when.js正是針對這樣的問題域。

讓我們來看看改造後的程式碼。

任務1:

複製程式碼 程式碼如下:

var getRssAddress = function(path) {
    var deferred = when.defer();
      fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
        if (err) deferred.reject(err);
        deferred.resolve(data);
      });

    return deferred.promise;
}


 
任務2:

複製程式碼 程式碼如下:

var getRss = 函數(url) {
  var deferred = when.defer();
    var data = '';
    http.get(url, 函數(res) {
      res.on('data', function(chrunk) {
        資料 = 區塊;
      });
      res.on('end', function() {
        deferred.resolve(資料);
      });
    }).on('錯誤', 函數(err) {
      deferred.reject(err);
    });

    返回 deferred.promise;
}

任務3:

複製程式碼程式碼如下:

var saveRss = 函數(data) {
  var deferred = when.defer();
  fs.writeFile('rss.txt', data, 'utf8', function(err) {
    if(err) deferred.reject(err);
    deferred.resolve();
  });

 回 deferred.promise;
}


 

整合:

複製程式碼程式碼如下:

getRssAddress('address.txt')
  .then(getRss)
  .then(saveRss)
  .catch(函數(錯誤) {
    console.log(錯誤);
  });

解釋:

promise/A規範定義的「Deferred/Promise」模型就是「發布/訂閱者」模型,透過Deferred物件發布事件,可以是完成resolve事件,或是失敗reject事件;透過Promise物件回覆完成或失敗的訂閱。

在Promises/A規格中,每個任務都有透明狀態:預設(pending)、完成(fulfilled)、失敗(rejected)。

1.預設狀態可以單向轉移到完成,這個過程叫做resolve,對應的方法是deferred.resolve(promiseOrValue);

2.預設狀態還可以單向轉移到失敗,這個過程叫做reject,對應的方法是deferred.reject(reason);

3.狀態預設時,也可以透過deferred.notify(update)來宣告任務執行訊息,如執行進度;

4.狀態的轉移是瞬時的,一旦任務由初始的pending轉為其他狀態,就會進入到下一個任務的執行過程中。

按照上面的程式碼。

透過when.defer定義一個deferred物件。

var deferred = when.defer();
非同步資料獲取成功後,發布一個完成事件。

deferred.resolve(數據);
非同步資料獲取失敗後,發布一個失敗事件。

deferred.reject(err);
並返回Promise物件作為訂閱使用。

返回 deferred.promise;
訂閱是透過Promise物件的then方法進行完成/失敗/通知的訂閱。

getRssAddress('address.txt')
  .then(getRss)
那麼有三個參數,分別是onFulfilled、onRejected、onProgress

promise.then(onFulfilled, onRejected, onProgress)
上一個任務被resolve(data),onFulfilled函數就會被觸發,data作為它的參數。

上一個任務被拒絕(原因),那麼onRejected就會被觸發,收到原因。

任何時候,onFulfilled和onRejected都只有其中一個可以被觸發,並且只觸發一次。

對於處理異常,when.js也提供了極為方便的方法,然後可以提交錯誤,多個任務串列執行時,我們可以只在最後一個then定義onRejected。也可以在最後一個then的後面呼叫catch函數捕捉任何一個任務的異常。

這樣寫法就簡單明了。

複製程式碼程式碼如下:

getRssAddress('address.txt')
  .then(getRss)
  .then(saveRss)
  .catch(函數(錯誤) {
    console.log(錯誤);
  });

Promise 為非同步程式設計帶來了巨大的方便,可以讓我們專注於單一任務的實現而不是瀑布金字塔厄運,除了以上程式碼的基本使用,when.js 提供的功能顯然不止本文提到的這些,具體參考官方API。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn