前一天我們看了簡單建立服務伺服器的方法,其中我們稍微的有提到事件驅動與callback()函數,今天在正式開始之前,我們先來聊聊一個在Coding NodeJS時常會犯下的錯誤。
我們先來看看底下這段程式碼
function factorialOperate(num, callback, tmpRS) {
    var rs = 0;
    if (!tmpRS) {
        rs = num * (num - 1);
    } else {
        rs = (num - 1) * tmpRS;
    }
    if (num - 1 > 1) {
        factorialOperate(num - 1, callback, rs);
    } else {
        return callback(rs);
    }
}
exports.factorialOperate = factorialOperate;
我們透過callback()做了一個用來計算階層的函數,這個函數其實可以簡單地透過for迴圈就可以達成,但由於示範的需求,於此把它寫成具有callback()型態的函數。
接著我們在寫一個主程式來呼叫此函數進行運算,大致內容大概像下方這樣:
function noTimeout() {
    var num1 = 10;
    var num2 = 5;
    var rs1 = 0;
    var rs2 = 0;
    var result = 0;
    console.log('===========No Timeout Start===========');
    factorialOperate(num1, function(rs){
        rs1 = rs;
        console.log(num1 + '! = ' + rs1);
    });
    factorialOperate(num2, function(rs){
        rs2 = rs;
        console.log(num2 + '! = ' + rs2);
    });
    result = rs1 + rs2;
    console.log(result);
    console.log('===========No Timeout End===========');
}
執行的結果畫面為下圖所示:
 
這執行結果看起來非常完美,沒有什麼不對。但記得,Node JS主要是作用於網路服務的程序,我們必須考慮到當大量演算,或網路傳輸延遲時會發生時,會發生怎樣的情況。
為此我們另外新增一個具有callback()的函數,並在其中加入了set timeout 100毫秒來模擬大量運算或網路延遲下的結果。
function factorialOperateWithTimeout(num, callback, tmpRS) {
    var rs = 0;
    if (!tmpRS) {
        rs = num * (num - 1);
    } else {
        rs = (num - 1) * tmpRS;
    }
    if (num - 1 > 1) {
        setTimeout(function() {
            factorialOperateWithTimeout(num - 1, callback, rs);
        }, 100);
    } else {
        return callback(rs);
    }
}
exports.factorialOperateWithTimeout = factorialOperateWithTimeout;
同樣的也寫一個主程序來呼叫此函數進行運算,大致內容大概像下方這樣:
function withTimeout() {
    var num1 = 10;
    var num2 = 5;
    var rs1 = 0;
    var rs2 = 0;
    var result = 0;
    console.log('===========With Timeout 100ms Start===========');
    factorialOperateWithTimeout(num1, function(rs){
        rs1 = rs;
        console.log(num1 + '! = ' + rs1);
    });
    factorialOperateWithTimeout(num2, function(rs){
        rs2 = rs;
        console.log(num2 + '! = ' + rs2);
    });
    result = rs1 + rs2;
    console.log(result);
    console.log('===========With Timeout 100ms End===========');
}
 
由圖中可以發現主控台所輸出的訊息好像不是我們想要的結果!?看起來似乎我們Set Timeout 100毫秒來模擬延遲效果,造成運算出來的結果順序不一,那到底該怎麼修正這種情況呢?
function useCallBack() {
    var num1 = 10;
    var num2 = 5;
    var rs1 = 0;
    var rs2 = 0
    var result = 0;
    console.log('===========use Callback Start===========');
    factorialOperateWithTimeout(num1, function(rs){
        rs1 = rs;
        console.log(num1 + '! = ' + rs1);
        factorialOperateWithTimeout(num2, function(rs){
            rs2 = rs;
            console.log(num2 + '! = ' + rs2);
            result = rs1 + rs2;
            console.log(result);
            console.log('===========use Callback End===========');
        });
    });
}
其實非常簡單,只要運用callback的方式,來把兩個 "factorialOperateWithTimeout()"呼叫語句串起來就好了,如上段程式碼內容所示。而執行結果就會像下圖一樣,達到我們想要的目標。

 

也許有朋友會問,那如果我們想要呼叫多個函數,並把這些函數的傳回結果相互交叉運算時,豈不是要在callback()裡面加上callback()?這樣call來call去,不會讓程式碼不好判讀,也很容易造成自己在開發時的混淆狀況嗎?

的確是如此... 所以在開發之前,可能就必須想好每個function之間的因果關係。但其實也不用這麼的緊張,明天讓我們來介紹一個好用的套件"async",到時讓我們來看看如何使用async來簡單的達到運算同步的需求。

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

低敘呢喃

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