前言
大家在編寫異步程序時,最頭痛的就是不知道結果什么時候返回給我們,然后執行后面的操作,很多時候只能把后面的操作放到返回成功的函數里,或者使用計數器等方法。
比較典型的兩個就是:后面的操作需要依賴上一個異步操作的結果;多個異步操作并行執行,都執行完成后再執行接下來的操作。
這兩個操作中,第一個異步的程序我們可能會寫成這樣:
db.select(SQL1, function(res1){ db.delete(SQL2, function(res2){ db.insert(SQL3, function(res3){ // ... }) })});將后面的操作寫到執行成功后的回調函數里。第2個并行的異步操作,可以使用計數器的方法,每個異步調用成功時,計數器加1,當所有的異步都調用成功后,再接著執行:
var count = 0;var success = function(){ count++; if(count>=3){ console.log('執行完畢...'); }}var select = function(){ db.select(sql, function(res){ success(); })}var select2 = function(){ db.select(sql, function(res){ success(); })}var select3 = function(){ db.select(sql, function(res){ success(); })}select();select2();select3();這些編寫方式非常麻煩,而且代碼邏輯比較混亂,調試起來也很不方便。那么就要用到異步控制的利器async了。
介紹
async的作用是進行流程的控制,而且提供了非常多的方法可供調用。
這些方法可以分為三大類:
下面我們從這三個分類里分別挑出幾個方法進行講解。
二、函數介紹
async中提供了非常多的方法可供使用,我們僅僅是講解其中幾個比較有代表性的,其他的可以訪問官方文檔:http://caolan.github.io/async/docs.html。
2.1 集合類
集合類中的方法主要有some, ‘map', ‘each', ‘every'等,這些方法是對數組或組合進行某個相同的操作后,統一執行回調函數。
我們以map為例,map對集合中的每一個元素,執行某個相同的異步操作,得到結果。所有的結果將匯總到最終的callback里。
使用方法,map接收三個參數,分別是:
| 參數名稱 | 類型 | 說明 |
| coll | iteratee | callback |
| Array | Iterable | Object | function | function |
| 需要處理數組,集合或其他可迭代的類型 | 迭代方法,用來對集合中的每一項進行處理。該方法接收兩個參數(item, callback);item為集合中的每一項, callback為回調函數。callback需要帶有err(有時可能為null)和處理后的數據,callback(err, data) | 最終回調函數,當集合處理完畢后調用此函數,傳遞兩個參數err和result,result為之前處理后的所有的結果的集合 |
注意:中間處理函數iteratee對coll中的每一項都是并發處理的,因此并不能保證iteratee按照順序完成。不過,如果coll是個數組,最后的結果集results會按照coll中的順序排列;如果coll是個集合(Object)類型,results會是數組類型,結果將大致按照coll的鍵的順序排列(但是不同在不同的JavaScript引擎中會有可能發生變化)。
我們來舉個例子,使用map獲取幾個文件中的內容:
var files = ['./file/cnode_1.txt', './file/cnode_2.txt', './file/cnode_3.txt'];// 讀取文件內容// 第1個參數 文件名稱列表的數組// 第2個參數 傳入數組中的每一項和回調函數// 第3個參數 results為所有結果的集合async.map(files, function(file, cb){ fs.readFile(file, 'utf-8', function(err, data){ cb(err, data); })}, function(err, results){ console.log( results );})而且,如果中間的處理函數比較大,不想寫在map中,也可以單獨寫成一個函數,然后傳遞進去,不過參數傳遞還是要符合規則的:
var files = ['./file/cnode_1.txt', './file/cnode_2.txt', './file/cnode_3.txt'];var read = function(file, cb){ fs.readFile(file, 'utf-8', function(err, data){ cb(err, data); })}async.map(files, read, function(err, result){ console.log( result );})這里還有一個mapLimit,可以傳遞一個參數limit,用來限制并發的數量:mapLimit(coll, limit, iteratee, callbackopt) :
// 并發數量為2async.mapLimit(files, 2, read, function(err, result){ console.log( result );})同時,集合類中還有其他的方法,我們也稍微了解下:
2.2 流程控制類
上面的集合類是對一個集合進行相同的處理,集合中的每一項都處理完后,再對結果進行回調處理。而多個回調方法執行時,則需要對這幾個回調方法進行控制了。
多個回調方法執行時,通常有這么幾個流程:
async.seriesasync.parallel當然還有其他更復雜的流程,這里也只聊上面的三種情況。
async.series,async.waterfall和async.parallel的語法都是一樣的:async.Method(coll, function(err, results){})其中coll既可以是數組,也可以是json格式的,而且results的類型與coll對應。
串行且無關聯async.series:
// 串行且無關聯,數組格式async.series([ function(cb){ getAllList(function(result){ cb(null, result); }); }, function(cb){ getAllUser(function(result){ cb(null, result); }); }], function(err, result){ console.log(result);})同時串行的異步可以是json格式的:
// 串行且無關聯,json個數async.series({ one: function(cb){ getAllList(function(result){ cb(null, result); }); }, two: function(cb){ getAllUser(function(result){ cb(null, result); }); }}, function(err, result){ console.log(result);})串行且有關聯async.waterfall:
// 串行且上一個結果作為下一個的參數async.waterfall([ function(cb){ getListById(1, function(result){ cb(null, result); }); }, function(params, cb){ console.log(params); getAllUser(function(result){ cb(null, result); }); }], function(err, result){ console.log(result);})并行async.parallel:
// 并行,getAllList與getAllUser同時執行async.parallel([ function(cb){ getAllList(function(result){ cb(null, result); }); }, function(cb){ getAllUser(function(result){ cb(null, result); }); }], function(err, result){ console.log(result);})關于并行的異步操作,這里還有一個async.parallelLimit,限制并發的數量:
// 并發數量為2async.parallelLimit([ iteratee1, iteratee2, iteratee3, ...], 2, function(err, results){ })2.3 工具類
async中也提供了不少的工具方法可供使用,比如async.log可以輸出回調方法中的值,第1個參數為函數,后面的參數為傳遞給函數的參數:
var hello = function(name, callback) { setTimeout(function() { callback(null, 'hello ' + name); }, 1000);};// 將'world'傳遞給hello方法async.log(hello, 'world'); // 'hello world'這里面還有apply, dir, timeout等方法。
總結
使用async控制異步流程非常的方便,而且也可以在前端使用,比如可以操作多個ajax請求等。好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。
新聞熱點
疑難解答