nodejs學習筆記 —— 非同步編程解決方案

來源:互聯網
上載者:User

標籤:blog   http   io   ar   使用   java   sp   div   on   

在js或者node編程中,由於非同步頻繁和廣度使用,使得回調和嵌套的深度導致編程的體驗遇到一些挑戰,如果寫出優雅和好看的代碼,本文主要針對非同步編程的主流方案做一些總結

1、事件發布/訂閱模式

事件監聽器模式是一種廣泛用於非同步編程的模式, 是回呼函數的事件化,又稱發布/訂閱模式, node自身提供events模組,是該模式的一個簡單實現。

EventPorxy 

2、promise/deferrd模式

在2009年被Kris Zyp抽象為一個提議草案,發布在CommonJS規範中, 目前,CommonJS草案中已經包括Promise/A、Promise/B、Promise/D這些非同步模型。由於Promise/A較為常用也較為簡單,只需要具備then()方法即可。所以先介紹一些改模式。

一般來說,then()的方法定義如下:

then(fulfilledHandler, errorHandler, progressHandler)
Promises/A

通過繼承Node的events模組,我們可以實現一個簡單Promise模組。

promise部分

var Promise = function() {    EventEmitter.call(this);}util.inherits(Promise, EventEmitter); // util是node內建的工具類 Promise.prototype.then = function(fulfilledHandler, errorHandler, progressHandler) {    if(typeof fulfilledHandler === "function") {        this.once(‘success‘, fulfilledHandler);    }    if(typeof errorHandler === "function") {        this.once(‘error‘, errorHandler);    }    if(typeof progressHandler === "function") {        this.on(‘progress‘, progressHandler);    }    return this;} 

deferred部分

var Deferred = function() {    this.state = ‘unfulfilled‘;    this.promise = new Promise();} Deferred.prototype.resolve = function(obj) {    this.state = ‘fulfilled‘;    this.promise.emit(‘success‘, obj);} Deferred.prototype.reject = function(obj) {    this.state = ‘failed‘;    this.promise.emit(‘error‘, obj);} Deferred.prototype.progress = function(obj) {    this.promise.emit(‘progress‘, obj);}

使用

function readFile(file, encoding) {      var deferred = new Deferred();      fs.readFile(file, encoding, deferred.resolve);      return deferred.promise;}readFile(‘/test.txt‘,  ‘utf-8‘).then(function(data) {      ... }, function(err) {      ...});    

以上是promise/deferred模式的簡單實現,狀態轉換圖可以描述如下:

promise模式比發布/訂閱模式略為優雅, 但還不能滿足很多情境的實際需求,比如一組純非同步API為了協同完成一串事情。 

Promises/A+

規範將之前 Promises/A 規範的建議明確為了行為標準。其擴充了原規範以覆蓋一些約定俗成的行為,以及省略掉一些僅在特定情況下存在的或者有問題的部分

詳見:中文版:http://www.ituring.com.cn/article/66566, 英文版:https://promisesaplus.com/

3、流程式控制制庫尾觸發與next

尾觸發目前應用最多的地方是Connect的中介軟體, 中介軟體處理網路請求時,可以向面向切面編程一樣進行過濾、驗證、日誌等功能,最簡單的中介軟體如下:

function(req, res, next) {     //中介軟體      }

每個中介軟體傳遞請求對象、響應對象和尾觸發函數,通過隊列形成一個處理流,如下:

  

看一個例子

app.use(function(req, res, next) {    setTimeout(function() {        next();     }, 0) }, function(req, res, next) {    setTimeout(function() {         next();     }, 0);});

從這個執行個體中可以簡單猜到尾觸發的實現原理了,簡單講就是通過調用use維護一個隊列, 調用next的時候出隊並執行,依次迴圈。

async

目前最知名的流程式控制制模組,async模組提供了20多個方法用於處理非同步多種寫作模式, 如:

1、非同步串列執行

async.series([    function(callback){        // do some stuff ...        callback(null, ‘one‘);    },    function(callback){        // do some more stuff ...        callback(null, ‘two‘);    }],// optional callbackfunction(err, results){    // results is now equal to [‘one‘, ‘two‘]});

// an example using an object instead of an arrayasync.series({    one: function(callback){        setTimeout(function(){            callback(null, 1);        }, 200);    },    two: function(callback){        setTimeout(function(){            callback(null, 2);        }, 100);    }},function(err, results) {    // results is now equal to: {one: 1, two: 2}});  

異常處理原則是一遇到異常,即結束所有調用,並將異常傳遞給最終回呼函數的第一個參數

2、非同步並存執行

// an example using an object instead of an arrayasync.parallel({    one: function(callback){        setTimeout(function(){            callback(null, 1);        }, 200);    },    two: function(callback){        setTimeout(function(){            callback(null, 2);        }, 100);    }},function(err, results) {    // results is now equals to: {one: 1, two: 2}});

與EventProxy基於事件發布和訂閱模式的不同在於回呼函數的使用上, async回呼函數由async封裝後傳入, 而EventProxy則通過done(), fail()方法來產生新的回呼函數, 實現方式都是高階函數的應用。

3、非同步呼叫的依賴處理

async.waterfall([    function(callback){        callback(null, ‘one‘, ‘two‘);    },    function(arg1, arg2, callback){       // arg1 now equals ‘one‘ and arg2 now equals ‘two‘        callback(null, ‘three‘);    },    function(arg1, callback){        // arg1 now equals ‘three‘        callback(null, ‘done‘);    }], function (err, result) {   // result now equals ‘done‘    });

4、自動依賴處理

async.auto({    get_data: function(callback){        console.log(‘in get_data‘);        // async code to get some data        callback(null, ‘data‘, ‘converted to array‘);    },    make_folder: function(callback){        console.log(‘in make_folder‘);        // async code to create a directory to store a file in        // this is run at the same time as getting the data        callback(null, ‘folder‘);    },    write_file: [‘get_data‘, ‘make_folder‘, function(callback, results){        console.log(‘in write_file‘, JSON.stringify(results));        // once there is some data and the directory exists,        // write the data to a file in the directory        callback(null, ‘filename‘);    }],    email_link: [‘write_file‘, function(callback, results){        console.log(‘in email_link‘, JSON.stringify(results));        // once the file is written let‘s email a link to it...        // results.write_file contains the filename returned by write_file.        callback(null, {‘file‘:results.write_file, ‘email‘:‘[email protected]‘});    }]}, function(err, results) {    console.log(‘err = ‘, err);    console.log(‘results = ‘, results);});

在現實的業務環境中,具有很多複雜的依賴關係, 並且同步和非同步也不確定,為此auto方法能根據依賴關係自動分析執行。

Step

輕量的async, 在API暴露上也具備一致性, 因為只有一個介面Step。 

在非同步處理上有一些不同, Step一旦產生異常,會將異做為下一個方法的第一個參數傳入

var s = require(‘step‘);s(    function readSelf() {        fs.readFile(__filename, this);    },      function(err, content) {        //並存執行任務        fs.readFile(__filename, this.parallel());        fs.readFile(__filename, this.parallel());    },      function() {
//任務分組儲存結果 var group = this.group(); console.log(arguments); fs.readFile(__filename, group()); fs.readFile(__filename, group()); }, function () { console.log(arguments); } )
Wind

待補充

 

總結

對比幾種方案的區別:事件發布/訂閱模式相對是一種原始的方式,Promise/Deferred模式貢獻了一個非常不錯的非同步任務模型的抽象,重頭在於封裝非同步調用部分, 而流程式控制制庫則要靈活很多。

除了async、step、EventProxy、wind等方案外,還有一類通過原始碼編譯的方案來實現流程式控制制的簡化, streamline是一個典型的例子。

 

參考

《深入淺出nodejs》第四章

https://promisesaplus.com/

https://github.com/caolan/async/

https://github.com/creationix/step

http://www.ituring.com.cn/article/66566

 

nodejs學習筆記 —— 非同步編程解決方案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.