1. 程式人生 > >JavaScript,Node.js 巢狀非同步呼叫的實現以及注意點

JavaScript,Node.js 巢狀非同步呼叫的實現以及注意點

前言

使用Node.js實現伺服器端時,需要處理不少的非同步請求。
有些時候,我們會遇到這種情況:
對於某個數組裡面的字串,你需要依次地通過非同步呼叫的方法向資料庫請求資料,即,我先用第一個字串提交請求,然後在回撥函式中用第二個字串提交請求,以此類推,我們就要像這樣呼叫程式碼,即:

/*
    *假設有非同步函式非同步傳回
    A(para, callback){
        ...
        得到結果result
        ...
        callback(result);
    }
    我們要對如下字串陣列的每一項呼叫A
    data[]
*/
A(data[0], function(result1){ //處理result1 A(data[1], function(result2){ //處理result2 ...... }); });

然而很多時候,我們對於result的處理是相同的,而且寫多層巢狀實在是不美觀,且工作量巨大。
此時我們就可以用一個迴圈來實現函式的巢狀。

思路

我們需要指定一個函式陣列fun_list[],並讓每個函式都長成下面這樣

fun_list[i] = function(){
    A(data[i], function(result){
        /*處理result*/
fun_list[i+1](); //呼叫下一個函式陣列中的函式 //最後一個函式就不用往下呼叫了 }); }

這樣,我們只要呼叫fun_list[0]();就可以實現巢狀非同步呼叫。

很容易想到通過一個迴圈來實現這個陣列,就像下面這樣:


for(var i = 0; i < data.length;i++){
    fun_list.push(function(){
        A(data[i], function(result){
        /*處理result*/
            fun_list[i+1
](); }); }); } fun_list.push(function(){ /*不做處理,或者做陣列處理完成之後的工作*/ }); fun_list[0]();

看到這裡,興奮地去嘗試上述程式碼,你會發現,直接就報錯了。

JavaScript的特性

造成問題的原因是,函式陣列中的i,並不是一個常量,而是一個變數i。也就是說,在迴圈完成時,所有的i都會變成data.length,而data[data.length]是沒定義的,所以就報錯了。

這個也是JavaScript的一個小特性,為了支援非同步,傳入的i是一個變數,而即使出了for迴圈,這個i仍舊是存在的。所以我們作出一點小修改,將變數變成一個常量。

修改

我們可以在呼叫function時傳入,這個是第幾個function,對於這個傳入值,則是每個函式都是唯一的,程式碼修改如下:


for(var i = 0; i < data.length;i++){
    fun_list.push(function(j){
        A(data[j], function(result){
        /*處理result*/
            fun_list[j+1](j+1);
        });
    });
}

fun_list.push(function(j){
    /*不做處理,或者做陣列處理完成之後的工作*/
});

fun_list[0](0);

經過這番修改,就能夠實現巢狀非同步呼叫了。