nodejs流程控制之a(chǎn)sync

本文主要講解async的函數(shù): series,parallel, waterfall 函數(shù)的理解和 使用

async 函數(shù)是什么?

一句話,async 函數(shù)就是 Generator 函數(shù)的語法糖。

背景:
Node.js 使用事件驅(qū)動(dòng),非阻塞I/O 模型而得以輕量和高效。
事件發(fā)生后交由指定的程序處理,處理完成后就調(diào)用事件回調(diào)函數(shù)。回調(diào)機(jī)制使用Node.js具有了強(qiáng)大的并發(fā)處理能力,但也帶來了一系列的回調(diào)嵌套問題。

async解決了什么問題?

解決回調(diào)嵌套的方法有很多,如:async、promise、事件發(fā)射器等。幾種方案多少都使用過,今天介紹一下async中的常用方法。本篇主要介紹其流程控制部分。

async 提供的api包括三個(gè)部分::

  • 流程控制
  • 集合處理
  • 工具

流程控制常用的方法有:

series、parallel、waterfall、whilst、auto等。

這些方法功能如下:

  • series:多個(gè)任務(wù)依次執(zhí)行
  • parallel:多個(gè)任務(wù)并發(fā)執(zhí)行
  • waterfall:多個(gè)任務(wù)依次執(zhí)行,上一任務(wù)的輸出可做為下一任務(wù)的輸入?yún)?shù)
  • whilst:while循環(huán)執(zhí)行任務(wù),但本次任務(wù)執(zhí)行完畢后才會(huì)進(jìn)入下一次循環(huán)
  • auto:根據(jù)任務(wù)需要選擇順序或并發(fā)執(zhí)行任務(wù)

下面重點(diǎn)介紹series、parallel、waterfall:

安裝方法: npm install async
使用方法: var async=require('async');

1.Async.series(tasks, [callback])

  • 用法:

series方法用于依次執(zhí)行(串行執(zhí)行)多個(gè)方法
一個(gè)方法執(zhí)行完畢后才會(huì)進(jìn)入下一方法
方法之間沒有數(shù)據(jù)傳遞

  • 參數(shù)
    • tasks:需要執(zhí)行多個(gè)方法。tasks可以以數(shù)組形式傳入,也可以以object對(duì)象形式傳入。參數(shù)類型不同,影響的是返回?cái)?shù)據(jù)的格式。每個(gè)方法都要一個(gè)回調(diào)方法
  • callback(err, result),用于處理錯(cuò)誤或進(jìn)入下一方法。當(dāng)發(fā)生錯(cuò)誤時(shí)(即:err參數(shù)存在時(shí)),其后的方法會(huì)跳過,錯(cuò)誤被傳入最終回調(diào)方法中。
    callback(err, results):可選的最終回調(diào)方法。出錯(cuò)時(shí),tasks中拋出的錯(cuò)誤將在此方法中捕獲,錯(cuò)誤被傳入err參數(shù)。不出錯(cuò)時(shí),tasks中回調(diào)結(jié)果將被寫入results參數(shù)中,以數(shù)據(jù)或?qū)ο笮问教峁?/li>
  • 實(shí)例
var async = require('async');
//以數(shù)組形式傳入需要執(zhí)行的多個(gè)方法
async.series([
    function(callback){
        // 執(zhí)行一些操作后,callback進(jìn)入下一方法
        callback(null, 'one');
    },
    function(callback){
        // 執(zhí)行一些操作后,callback進(jìn)入可選的最終回調(diào)方法
        callback(null, 'two');
    }
],
// 可選的最終回調(diào) 
function(err, results){
    // 當(dāng)tasks中的任一方法發(fā)生錯(cuò)誤,即回調(diào)形式為callback('錯(cuò)誤信息')時(shí),錯(cuò)誤將被傳遞給err參數(shù),未發(fā)生錯(cuò)誤err參數(shù)為空
    // results中為數(shù)組中兩個(gè)方法的結(jié)果數(shù)組:['one', 'two'] 
});
 


//以object對(duì)象形式傳入需要執(zhí)行的多個(gè)方法
async.series({
    one: function(callback){
        // 執(zhí)行一些操作后,callback進(jìn)入下一方法
        callback(null, 1);
    },
    two: function(callback){
        // 執(zhí)行一些操作后,callback進(jìn)入可選的最終回調(diào)方法
        callback(null, 2);
    }
},
function(err, results) {
    // 當(dāng)tasks中的任一方法發(fā)生錯(cuò)誤,即回調(diào)形式為callback('錯(cuò)誤信息')時(shí),錯(cuò)誤將被傳遞給err參數(shù),未發(fā)生錯(cuò)誤err參數(shù)為空
    // results中為數(shù)組中兩個(gè)方法的結(jié)果對(duì)象:{one: 1, two: 2} 
});

該函數(shù)的詳細(xì)解釋為

  1. 依次執(zhí)行一個(gè)函數(shù)數(shù)組中的每個(gè)函數(shù),每一個(gè)函數(shù)執(zhí)行完成之后才能執(zhí)行下一個(gè)函數(shù)。
  2. 如果任何一個(gè)函數(shù)向它的回調(diào)函數(shù)中傳了一個(gè)error,則后面的函數(shù)都不會(huì)被執(zhí)行,并且將會(huì)立刻會(huì)將該error以及已經(jīng)執(zhí)行了的函數(shù)的結(jié)果,傳給series中最后那個(gè)callback。
  3. 當(dāng)所有的函數(shù)執(zhí)行完后(沒有出錯(cuò)),則會(huì)把每個(gè)函數(shù)傳給其回調(diào)函數(shù)的結(jié)果合并為一個(gè)數(shù)組,傳給series最后的那個(gè)callback。
  4. 還可以json的形式來提供tasks。每一個(gè)屬性都會(huì)被當(dāng)作函數(shù)來執(zhí)行,并且結(jié)果也會(huì)以json形式傳給series最后的那個(gè)callback。這種方式可讀性更高一些。
  • 需要注意的是:
  • 如果中間某個(gè)函數(shù)出錯(cuò),series函數(shù)如何處理

  • 思考一下:如果某個(gè)函數(shù)傳給回調(diào)的值為undefined, null, {}, []等,series如何處理

另外還需要注意的是:多個(gè)series調(diào)用之間是不分先后的,因?yàn)閟eries本身也是異步調(diào)用。

2. parallel(tasks, [callback])

  • 執(zhí)行原理

parallel方法用于 并行執(zhí)行 多個(gè)方法,所有傳入的方法都是立即執(zhí)行,方法之間沒有數(shù)據(jù)傳遞。傳遞給最終callback的數(shù)組中的數(shù)據(jù)按照tasks中聲明的順序,而不是執(zhí)行完成的順序。

  • 參數(shù)
  • ** tasks:需要執(zhí)行多個(gè)方法。tasks可以以 *** 數(shù)組形式傳入,也可以以object對(duì)象*形式傳入。和series函數(shù)一樣,tasks參數(shù)類型不同,返回的results格式會(huì)不一樣。
    每個(gè)方法都要一個(gè)回調(diào)方法callback(err, result),回調(diào)方法需要提供一個(gè)err參數(shù)或是result參數(shù)。

當(dāng)如果某個(gè)函數(shù)出錯(cuò),則立刻將err和已經(jīng)執(zhí)行完的函數(shù)的結(jié)果值傳給parallel最終的callback。其它未執(zhí)行完的函數(shù)的值不會(huì)傳到最終數(shù)據(jù),但要占個(gè)位置。

  • callback(err, results):可選的最終回調(diào)方法。出錯(cuò)時(shí),tasks中拋出的錯(cuò)誤將在此方法中捕獲,錯(cuò)誤被傳入err參數(shù)。不出錯(cuò)時(shí),tasks中回調(diào)結(jié)果將被寫入results參數(shù)中,以數(shù)據(jù)或?qū)ο笮问教峁?/li>
  • 示例
 //以數(shù)組形式傳入需要執(zhí)行的多個(gè)方法
async.parallel([
    function(callback){
        // 執(zhí)行一些操作后,callback表示本方法執(zhí)行完成
        callback(null, 'one');
    },
    function(callback){
        // 執(zhí)行一些操作后,callback表示本方法執(zhí)行完成
        callback(null, 'two');
    }
],
// 可選的最終回調(diào) 
function(err, results){
    // 當(dāng)tasks中的任一方法發(fā)生錯(cuò)誤,即回調(diào)形式為callback('錯(cuò)誤信息')時(shí),錯(cuò)誤將被傳遞給err參數(shù),未發(fā)生錯(cuò)誤err參數(shù)為空
    // results中為數(shù)組中兩個(gè)方法的結(jié)果數(shù)組:['one', 'two'] ,即使第二個(gè)方法先執(zhí)行完成,其結(jié)果也是在第一個(gè)方法結(jié)果之后
});
 
//以object對(duì)象形式傳入需要執(zhí)行的多個(gè)方法
async.parallel({
    one: function(callback){
        // 執(zhí)行一些操作后,callback表示本方法執(zhí)行完成
        callback(null, 1);
    },
    two: function(callback){
        // 執(zhí)行一些操作后,callback表示本方法執(zhí)行完成
        callback(null, 2);
    }
},
function(err, results) {
    // 當(dāng)tasks中的任一方法發(fā)生錯(cuò)誤,即回調(diào)形式為callback('錯(cuò)誤信息')時(shí),錯(cuò)誤將被傳遞給err參數(shù),未發(fā)生錯(cuò)誤err參數(shù)為空
    // results中為數(shù)組中兩個(gè)方法的結(jié)果對(duì)象:{one: 1, two: 2} 
});

3. waterfall(tasks, [callback])

  • 用法

waterfall方法與series方法類似用于依次執(zhí)行多個(gè)方法,一個(gè)方法執(zhí)行完畢后才會(huì)進(jìn)入下一方法

不同與series方法的是:
waterfall之間有數(shù)據(jù)傳遞。
waterfall的多個(gè)方法只能以數(shù)組形式傳入,不支持object對(duì)象。

  • 參數(shù)
  • tasks:需要執(zhí)行多個(gè)方法。tasks只能以數(shù)組形式傳入。每個(gè)方法都要一個(gè)回調(diào)方法callback(err, result1, result2, ...),用于處理錯(cuò)誤或進(jìn)入下一方法。

    當(dāng)發(fā)生錯(cuò)誤時(shí)(即:err參數(shù)存在時(shí)),其后的方法會(huì)跳過,錯(cuò)誤被傳入最終回調(diào)方法中。無錯(cuò)誤時(shí)回調(diào)參數(shù)result1, result2……將做為下一方法的輸入?yún)?shù)

  • callback(err, results):可選的最終回調(diào)方法。出錯(cuò)時(shí),tasks中拋出的錯(cuò)誤將在此方法中捕獲,錯(cuò)誤被傳入err參數(shù)。不出錯(cuò)時(shí),tasks中回調(diào)結(jié)果results為最后一個(gè)方法的回調(diào)結(jié)果。

  • 示例
async.waterfall([
    function(callback) {
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback) {
        // arg1 現(xiàn)在是 'one', arg2 現(xiàn)在是 'two' 
        callback(null, 'three');
    },
    function(arg1, callback) {
        // arg1 現(xiàn)在是 'three' 
        callback(null, 'done');
    }
], function (err, result) {
    //執(zhí)行的任務(wù)中方法回調(diào)err參數(shù)時(shí),將被傳遞至本方法的err參數(shù)
    // 參數(shù)result為最后一個(gè)方法的回調(diào)結(jié)果'done'     
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ** Async ** 機(jī)制 是什么? Async 是一個(gè)流程控制工具包,提供了直接而強(qiáng)大的異步功能?;?*...
    rangel閱讀 1,806評(píng)論 2 6
  • 1.nodejs 異步操作小test setTimeout(function(){ console.log('as...
    松愛家的小秦閱讀 503評(píng)論 0 0
  • Node基本 node的最大特性莫過于基于事件驅(qū)動(dòng)的非阻塞I/O模型。 node通過事件驅(qū)動(dòng)的方式處理請(qǐng)求,無須為...
    AkaTBS閱讀 2,304評(píng)論 0 11
  • 異步編程對(duì)JavaScript語言太重要。Javascript語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程,根本...
    呼呼哥閱讀 7,399評(píng)論 5 22
  • 文件系統(tǒng)模塊是一個(gè)封裝了標(biāo)準(zhǔn)的 POSIX 文件 I/O 操作的集合。通過require('fs')使用這個(gè)模塊。...
    保川閱讀 923評(píng)論 0 0

友情鏈接更多精彩內(nèi)容