前一日我們提到了在開發NodeJS中常會犯的錯誤,也就是當使用callback來處理大量數據,或因網路延遲而導致程序前後因果關係的混亂,此點流程控制上的手段就必須使用callback()包覆callback()的方式,來解決所可能產生的錯誤。

撇除這種非常不人性得程式碼編撰手法,我們可以使用現成的第三方套件”async”,來達成程序控制上的各種需求。在我們開始之前,請先透過npm install async來安裝相關套件,於此就不再解釋什麼是npm install,也不再說明為什麼async套件要以local的方式來進行安裝。

async套件的功能非常強大,它可以針對collection、control flow與utils來進行操作。

我們大多數會用到的情況,基本上為collection裡面的each與eachSeries、control flow裡面的waterfall、auto、whilst與doWhilst、until與doUntil,以及during與doDuring。

首先我們來看看collection的each與eachSeries,each與eachSeries顧名思義就是取得collection中的每個unit,再針對每個unit來進行操作。程序會在目前指標所在的unit操作完畢之後,才會跳至下一個unit,以此來控制程序流程的發展。

底下程式碼延續昨天的範例,但以陣列型態進行改寫,並透過eachSeries來處理程式運行。首先我們的”factorialOperateWithTimeout()”函數內容不變,僅於程式開頭處引入async套件,並修改主要執行程序部分:

var async = require('async');
function usingAsyncEachSeries() {
    var numsArray = [10, 5];
    var resultArray = [];
    console.log('===========use EachSeries Start===========');
    async.eachSeries(numsArray, function(num, doneOfEach){
        factorialOperateWithTimeout(num, function(rs){
            console.log(num + '! = ' + rs);
            resultArray.push(rs);
            return doneOfEach(null);
        });
    }, function(err, rs) {
        if (!err) {
            var sum = 0;
            for (var i = 0; i < resultArray.length; i ++) {
                sum += resultArray[i];
            }
            console.log('sum = ' + sum);
        }
        console.log('===========use EachSeries End===========');
    });
}

 

於程序中我們使用async.eachSeries,來將陣列numsArray的每個索引內容取出,並轉存入num變數中傳遞至callback()函數。

接著於callback函數function(num, doOfEach)內,呼叫factorialOperateWithTimeout()進行數學階層運算處理,結果傳回後再將結果轉存入resultArray陣列之中。這邊有一個比較需要注意的地方。doOfEach為一個callback函數,所以在每一次做完async.eachSeries的callback後,都必須要使用return doneOfEach(),來進行下一個索引值內容的運算。這邊我們使用doneOfEach(null)來作為結尾,代表在呼叫下一個陣列內容索引值時,不會傳遞任何數值過去。當陣列的所有索引值內容處理完畢後,會跳至function(err, rs)這個callback函數,來進行最後的處理動作。因此在這個區塊內,我們將轉存至resultArray陣列的內容依序取出,做SUM的運算處理。

這裡必須注意一件事情,最後的callback函數function(err, rs),其參數值有兩個。一個是err,用以方便做各種例外處理使用。也就是說,如果在eachSeries發生錯誤時,我們可以修改return doneOfEach(null)這段敘述,改為 return doneOfEach(err, rs) 其中err可以作為錯誤訊息,rs可以傳遞相關數值此時程序會即刻中斷eachSeries的工作,直接跳至最後的callback函數function(err, rs),進行最後的收尾處理工作。

each、eachSeries與eachLimit的使用方式十分雷同,查別僅在於each就是單純的陣列遍循運算,而eachSeries允許使用者加上iterator處理,最後eachLimit除了iterator外,更可讓開發人員加上Limit限制。相對於我們介紹的each、eachSeries與eachLimit是對陣列做遍循運算動作,那如果是物件呢?其實可以使用forEachOf、forEachOfSeries與forEachOfLimit,來做對應運算。相關的使用方式呢?請與陣列時差不了多少,請參照https://github.com/caolan/async#forEachOf的內容說明即可,於此不再多做累述。

Okay,我想第三天就到這邊就好,我們第四天再來討論control flow裡面的async.waterfall的使用方式吧。

文章標籤
全站熱搜
創作者介紹
創作者 alexlyblue 的頭像
alexlyblue

低敘呢喃

alexlyblue 發表在 痞客邦 留言(0) 人氣(370)