Nodejs 回調

2018-09-28 20:30 更新

回調

NodeJS 最大的賣點——事件機制和異步 IO,對開發(fā)者并不是透明的。開發(fā)者需要按異步方式編寫代碼才用得上這個賣點,而這一點也遭到了一些 NodeJS 反對者的抨擊。但不管怎樣,異步編程確實是 NodeJS 最大的特點,沒有掌握異步編程就不能說是真正學會了 NodeJS。本章將介紹與異步編程相關的各種知識。

在代碼中,異步編程的直接體現(xiàn)就是回調。異步編程依托于回調來實現(xiàn),但不能說使用了回調后程序就異步化了。我們首先可以看看以下代碼。

function heavyCompute(n, callback) {
    var count = 0,
        i, j;

    for (i = n; i > 0; --i) {
        for (j = n; j > 0; --j) {
            count += 1;
        }
    }

    callback(count);
}

heavyCompute(10000, function (count) {
    console.log(count);
});

console.log('hello');

-- Console ------------------------------
100000000
hello

可以看到,以上代碼中的回調函數(shù)仍然先于后續(xù)代碼執(zhí)行。JS 本身是單線程運行的,不可能在一段代碼還未結束運行時去運行別的代碼,因此也就不存在異步執(zhí)行的概念。

但是,如果某個函數(shù)做的事情是創(chuàng)建一個別的線程或進程,并與JS主線程并行地做一些事情,并在事情做完后通知 JS 主線程,那情況又不一樣了。我們接著看看以下代碼。

setTimeout(function () {
    console.log('world');
}, 1000);

console.log('hello');

-- Console ------------------------------
hello
world

這次可以看到,回調函數(shù)后于后續(xù)代碼執(zhí)行了。如同上邊所說,JS 本身是單線程的,無法異步執(zhí)行,因此我們可以認為 setTimeout 這類 JS 規(guī)范之外的由運行環(huán)境提供的特殊函數(shù)做的事情是創(chuàng)建一個平行線程后立即返回,讓 JS 主進程可以接著執(zhí)行后續(xù)代碼,并在收到平行進程的通知后再執(zhí)行回調函數(shù)。除了 setTimeout、setInterval 這些常見的,這類函數(shù)還包括 NodeJS 提供的諸如 fs.readFile 之類的異步 API。

另外,我們?nèi)匀换氐?JS 是單線程運行的這個事實上,這決定了 JS 在執(zhí)行完一段代碼之前無法執(zhí)行包括回調函數(shù)在內(nèi)的別的代碼。也就是說,即使平行線程完成工作了,通知 JS 主線程執(zhí)行回調函數(shù)了,回調函數(shù)也要等到 JS 主線程空閑時才能開始執(zhí)行。以下就是這么一個例子。

function heavyCompute(n) {
    var count = 0,
        i, j;

    for (i = n; i > 0; --i) {
        for (j = n; j > 0; --j) {
            count += 1;
        }
    }
}

var t = new Date();

setTimeout(function () {
    console.log(new Date() - t);
}, 1000);

heavyCompute(50000);

-- Console ------------------------------
8520

可以看到,本來應該在1秒后被調用的回調函數(shù)因為 JS 主線程忙于運行其它代碼,實際執(zhí)行時間被大幅延遲。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號