從零學(xué)習(xí)node.js之詳解異步控制工具async(八)
前言
大家在編寫異步程序時(shí),最頭痛的就是不知道結(jié)果什么時(shí)候返回給我們,然后執(zhí)行后面的操作,很多時(shí)候只能把后面的操作放到返回成功的函數(shù)里,或者使用計(jì)數(shù)器等方法。
比較典型的兩個(gè)就是:后面的操作需要依賴上一個(gè)異步操作的結(jié)果;多個(gè)異步操作并行執(zhí)行,都執(zhí)行完成后再執(zhí)行接下來(lái)的操作。
這兩個(gè)操作中,第一個(gè)異步的程序我們可能會(huì)寫成這樣:
db.select(SQL1, function(res1){ db.delete(SQL2, function(res2){ db.insert(SQL3, function(res3){ // ... }) }) });
將后面的操作寫到執(zhí)行成功后的回調(diào)函數(shù)里。第2個(gè)并行的異步操作,可以使用計(jì)數(shù)器的方法,每個(gè)異步調(diào)用成功時(shí),計(jì)數(shù)器加1,當(dāng)所有的異步都調(diào)用成功后,再接著執(zhí)行:
var count = 0; var success = function(){ count++; if(count>=3){ console.log('執(zhí)行完畢...'); } } 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();
這些編寫方式非常麻煩,而且代碼邏輯比較混亂,調(diào)試起來(lái)也很不方便。那么就要用到異步控制的利器async了。
介紹
async的作用是進(jìn)行流程的控制,而且提供了非常多的方法可供調(diào)用。
這些方法可以分為三大類:
- 集合類(Collections)
- 流程控制類(Control Flow)
- 工具類(Utils)
下面我們從這三個(gè)分類里分別挑出幾個(gè)方法進(jìn)行講解。
二、函數(shù)介紹
async中提供了非常多的方法可供使用,我們僅僅是講解其中幾個(gè)比較有代表性的,其他的可以訪問(wèn)官方文檔:http://caolan.github.io/async/docs.html。
2.1 集合類
集合類中的方法主要有some, ‘map', ‘each', ‘every'等,這些方法是對(duì)數(shù)組或組合進(jìn)行某個(gè)相同的操作后,統(tǒng)一執(zhí)行回調(diào)函數(shù)。
我們以map為例,map對(duì)集合中的每一個(gè)元素,執(zhí)行某個(gè)相同的異步操作,得到結(jié)果。所有的結(jié)果將匯總到最終的callback里。
使用方法,map接收三個(gè)參數(shù),分別是:
參數(shù)名稱 | 類型 | 說(shuō)明 |
coll | iteratee | callback |
Array | Iterable | Object | function | function |
需要處理數(shù)組,集合或其他可迭代的類型 | 迭代方法,用來(lái)對(duì)集合中的每一項(xiàng)進(jìn)行處理。該方法接收兩個(gè)參數(shù)(item, callback);item為集合中的每一項(xiàng), callback為回調(diào)函數(shù)。callback需要帶有err(有時(shí)可能為null)和處理后的數(shù)據(jù),callback(err, data) | 最終回調(diào)函數(shù),當(dāng)集合處理完畢后調(diào)用此函數(shù),傳遞兩個(gè)參數(shù)err和result,result為之前處理后的所有的結(jié)果的集合 |
注意:中間處理函數(shù)iteratee對(duì)coll中的每一項(xiàng)都是并發(fā)處理的,因此并不能保證iteratee按照順序完成。不過(guò),如果coll是個(gè)數(shù)組,最后的結(jié)果集results會(huì)按照coll中的順序排列;如果coll是個(gè)集合(Object)類型,results會(huì)是數(shù)組類型,結(jié)果將大致按照coll的鍵的順序排列(但是不同在不同的JavaScript引擎中會(huì)有可能發(fā)生變化)。
我們來(lái)舉個(gè)例子,使用map獲取幾個(gè)文件中的內(nèi)容:
var files = ['./file/cnode_1.txt', './file/cnode_2.txt', './file/cnode_3.txt']; // 讀取文件內(nèi)容 // 第1個(gè)參數(shù) 文件名稱列表的數(shù)組 // 第2個(gè)參數(shù) 傳入數(shù)組中的每一項(xiàng)和回調(diào)函數(shù) // 第3個(gè)參數(shù) results為所有結(jié)果的集合 async.map(files, function(file, cb){ fs.readFile(file, 'utf-8', function(err, data){ cb(err, data); }) }, function(err, results){ console.log( results ); })
而且,如果中間的處理函數(shù)比較大,不想寫在map中,也可以單獨(dú)寫成一個(gè)函數(shù),然后傳遞進(jìn)去,不過(guò)參數(shù)傳遞還是要符合規(guī)則的:
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 ); })
這里還有一個(gè)mapLimit,可以傳遞一個(gè)參數(shù)limit,用來(lái)限制并發(fā)的數(shù)量:mapLimit(coll, limit, iteratee, callbackopt)
:
// 并發(fā)數(shù)量為2 async.mapLimit(files, 2, read, function(err, result){ console.log( result ); })
同時(shí),集合類中還有其他的方法,我們也稍微了解下:
- each : 與map類似,但是最后的回調(diào)函數(shù)里沒(méi)有results,each只循環(huán)不負(fù)責(zé)處理結(jié)果
- every : 中間處理函數(shù)iteratee的參數(shù)(err, boolean)需要傳遞一個(gè)boolean值,若所有選項(xiàng)的結(jié)果都為true,則results為true
- some : 與every類似,只是只要其中一個(gè)選項(xiàng)的結(jié)果為true,則results為true
- filter : 對(duì)coll進(jìn)行篩選,篩選出結(jié)果為true的結(jié)果
- reject : 與filter正好相反,篩選出結(jié)果為false的結(jié)果
- concat : 將每個(gè)異步操作的結(jié)果合并為一個(gè)數(shù)組
2.2 流程控制類
上面的集合類是對(duì)一個(gè)集合進(jìn)行相同的處理,集合中的每一項(xiàng)都處理完后,再對(duì)結(jié)果進(jìn)行回調(diào)處理。而多個(gè)回調(diào)方法執(zhí)行時(shí),則需要對(duì)這幾個(gè)回調(diào)方法進(jìn)行控制了。
多個(gè)回調(diào)方法執(zhí)行時(shí),通常有這么幾個(gè)流程:
- 串行且無(wú)關(guān)聯(lián),即執(zhí)行完一個(gè)后再依次執(zhí)行下一個(gè),且相互之間無(wú)數(shù)據(jù)交互,都執(zhí)行完后,再執(zhí)行最后的回調(diào)函數(shù)。可以使用
async.series
- 串行且有關(guān)聯(lián),即執(zhí)行完一個(gè)后再依次執(zhí)行下一個(gè),且上一個(gè)回調(diào)函數(shù)的結(jié)果會(huì)作為下一個(gè)回調(diào)函數(shù)的參數(shù)。可以使用async.waterfall
- 并行,這幾個(gè)回調(diào)函數(shù)同時(shí)并發(fā)執(zhí)行,都執(zhí)行完成后,再執(zhí)行最后的回調(diào)函數(shù)??梢允褂?code>async.parallel
當(dāng)然還有其他更復(fù)雜的流程,這里也只聊上面的三種情況。
async.series,async.waterfall和async.parallel的語(yǔ)法都是一樣的: async.Method(coll, function(err, results){ })
其中coll既可以是數(shù)組,也可以是json格式的,而且results的類型與coll對(duì)應(yīng)。
串行且無(wú)關(guān)聯(lián)async.series
:
// 串行且無(wú)關(guān)聯(lián),數(shù)組格式 async.series([ function(cb){ getAllList(function(result){ cb(null, result); }); }, function(cb){ getAllUser(function(result){ cb(null, result); }); } ], function(err, result){ console.log(result); })
同時(shí)串行的異步可以是json格式的:
// 串行且無(wú)關(guān)聯(lián),json個(gè)數(shù) 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); })
串行且有關(guān)聯(lián)async.waterfall
:
// 串行且上一個(gè)結(jié)果作為下一個(gè)的參數(shù) 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同時(shí)執(zhí)行 async.parallel([ function(cb){ getAllList(function(result){ cb(null, result); }); }, function(cb){ getAllUser(function(result){ cb(null, result); }); } ], function(err, result){ console.log(result); })
關(guān)于并行的異步操作,這里還有一個(gè)async.parallelLimit
,限制并發(fā)的數(shù)量:
// 并發(fā)數(shù)量為2 async.parallelLimit([ iteratee1, iteratee2, iteratee3, ... ], 2, function(err, results){ })
2.3 工具類
async中也提供了不少的工具方法可供使用,比如async.log可以輸出回調(diào)方法中的值,第1個(gè)參數(shù)為函數(shù),后面的參數(shù)為傳遞給函數(shù)的參數(shù):
var hello = function(name, callback) { setTimeout(function() { callback(null, 'hello ' + name); }, 1000); }; // 將'world'傳遞給hello方法 async.log(hello, 'world'); // 'hello world'
這里面還有apply, dir, timeout等方法。
總結(jié)
使用async控制異步流程非常的方便,而且也可以在前端使用,比如可以操作多個(gè)ajax請(qǐng)求等。好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Nodejs 微信小程序消息推送的實(shí)現(xiàn)
這篇文章主要介紹了Nodejs 微信小程序消息推送的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01node.js實(shí)現(xiàn)簡(jiǎn)單爬蟲示例詳解
這篇文章主要為大家介紹了node.js實(shí)現(xiàn)簡(jiǎn)單爬蟲示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04nodejs語(yǔ)言實(shí)現(xiàn)驗(yàn)證碼生成功能的示例代碼
這篇文章主要介紹了nodejs語(yǔ)言實(shí)現(xiàn)驗(yàn)證碼生成功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10node省市區(qū)三級(jí)數(shù)據(jù)性能測(cè)評(píng)實(shí)例分析
這篇文章主要介紹了node省市區(qū)三級(jí)數(shù)據(jù)性能,結(jié)合具體實(shí)例形式評(píng)測(cè)分析了node省市區(qū)三級(jí)數(shù)據(jù)的實(shí)現(xiàn)、改進(jìn)方法與運(yùn)行效率,需要的朋友可以參考下2019-11-11node?NPM庫(kù)glob通配符匹配文件名minimatch模式匹配字符串學(xué)習(xí)
這篇文章主要為大家介紹了node?NPM庫(kù)glob通配符匹配文件名minimatch模式匹配字符串學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07nodejs微信開發(fā)之授權(quán)登錄+獲取用戶信息
這篇文章主要介紹了nodejs微信開發(fā)之授權(quán)登錄+獲取用戶信息,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03理解nodejs的stream和pipe機(jī)制的原理和實(shí)現(xiàn)
本篇文章主要介紹了理解nodejs的stream和pipe機(jī)制的原理和實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08npm出現(xiàn)Cannot?find?module?'XXX\node_modules\npm\bin\np
最近在啟動(dòng)項(xiàng)目的時(shí)候會(huì)報(bào)這個(gè)錯(cuò)就是npm丟失,所以下面這篇文章主要給大家介紹了關(guān)于npm出現(xiàn)Cannot?find?module?'XXX\node_modules\npm\bin\npm-cli.js'錯(cuò)誤的解決方法,需要的朋友可以參考下2022-08-08