2011-08-01 109 views
98

我試圖研究如何完全寫入異步函數。在翻閱了大量文檔之後,我仍然不清楚。如何爲Node.js編寫異步函數

如何爲Node編寫異步函數?我應該如何正確實現錯誤事件處理?

另一種問我問題的方法是:我應該如何解釋下面的函數?

var async_function = function(val, callback){ 
    process.nextTick(function(){ 
     callback(val); 
    }); 
}; 

另外,我發現this question on SO( 「我怎樣創建一個Node.js的異步非阻塞功能?」)有趣。我不覺得它已經回答了。

+13

這就是爲什麼我問。這對我來說並不明顯,這些功能有什麼不同。 – Kriem

+0

我建議你在你最喜歡的瀏覽器中查看'setTimeout'和'setInterval',並和他們一起玩。或者ajax回調函數(可能是最接近節點體驗的函數),或事件監聽器來處理你熟悉的事情,比如點擊和加載事件。異步模型已經存在於瀏覽器中,並且它們在節點中完全相同。 – davin

+0

@davin - 猜猜我沒有完全理解異步模型。 – Kriem

回答

77

您似乎混淆了異步IO與異步函數。 node.js使用異步非阻塞IO,因爲非阻塞IO更好。瞭解它的最好方法是觀看ryan dahl的一些視頻。

如何爲Node編寫異步函數?

只需編寫普通函數,唯一的區別是它們不是立即執行,而是作爲回調傳遞。

我應該如何實現錯誤事件處理正確

一般的API給你一個ERR作爲第一個參數的回調。例如

database.query('something', function(err, result) { 
    if (err) handle(err); 
    doSomething(result); 
}); 

是一種常見模式。

另一種常見模式是on('error')。例如

process.on('uncaughtException', function (err) { 
    console.log('Caught exception: ' + err); 
}); 

編輯:

var async_function = function(val, callback){ 
    process.nextTick(function(){ 
     callback(val); 
    }); 
}; 

以上功能時,稱爲

async_function(42, function(val) { 
    console.log(val) 
}); 
console.log(43); 

將打印42到控制檯異步。特別是process.nextTick在當前eventloop調用堆棧爲空之後觸發。在async_functionconsole.log(43)已運行後,該調用堆棧爲空。因此,我們打印43,然後是42.

您應該對事件循環進行一些閱讀。

+0

我已經看到了達爾vids,但我似乎沒有把握這個問題。 :( – Kriem

+1

@Kriem看到更新的答案並閱讀[關於事件循環](http://en.wikipedia.org/wiki/Event_loop) – Raynos

+1

感謝Fort的見解,我現在更加意識到我缺乏知識。 :)你最後一個例子的幫助。 – Kriem

2

試試這個,它適用於節點和瀏覽器。

isNode = (typeof exports !== 'undefined') && 
(typeof module !== 'undefined') && 
(typeof module.exports !== 'undefined') && 
(typeof navigator === 'undefined' || typeof navigator.appName === 'undefined') ? true : false, 
asyncIt = (isNode ? function (func) { 
    process.nextTick(function() { 
    func(); 
    }); 
} : function (func) { 
    setTimeout(func, 5); 
}); 
+16

4 downvotes甚至沒有一個建設性的評論..:\ – Omer

+6

@Omer這樣的生活就是這樣。 –

+0

@Omer代碼不言自明 –

6

只通過回調是不夠的。 您必須使用settimer來使函數異步。

例子: 不是異步功能:

function a() { 
    var a = 0;  
    for(i=0; i<10000000; i++) { 
    a++; 
    }; 
    b(); 
}; 

function b() { 
    var a = 0;  
    for(i=0; i<10000000; i++) { 
    a++; 
    };  
    c(); 
}; 

function c() { 
    for(i=0; i<10000000; i++) { 
    }; 
    console.log("async finished!"); 
}; 

a(); 
console.log("This should be good"); 

如果你運行上面的例子,這應該是很好的,將不得不等待,直到這些功能將完成工作。

僞多線程(異步)功能:

function a() { 
    setTimeout (function() { 
    var a = 0; 
    for(i=0; i<10000000; i++) { 
     a++; 
    }; 
    b(); 
    }, 0); 
}; 

function b() { 
    setTimeout (function() { 
    var a = 0; 
    for(i=0; i<10000000; i++) { 
     a++; 
    }; 
    c(); 
    }, 0); 
}; 

function c() { 
    setTimeout (function() { 
    for(i=0; i<10000000; i++) { 
    }; 
    console.log("async finished!"); 
    }, 0); 
}; 

a(); 
console.log("This should be good"); 

這一個將是真實地異步。 這應該是好的將在異步完成之前寫入。

0

如果你知道函數返回一個promise,我建議在JavaScript中使用新的異步/等待功能。它使語法看起來同步,但異步工作。當您添加async關鍵字的功能,它可以讓你await承諾在範圍:

async function ace() { 
    var r = await new Promise((resolve, reject) => { 
    resolve(true) 
    }); 

    console.log(r); // true 
} 

如果一個函數不返回一個承諾,我建議你定義一個新的承諾,其包裝,然後解析你想要的數據:

function ajax_call(url, method) { 
    return new Promise((resolve, reject) => { 
    fetch(url, { method }) 
    .then(resp => resp.json()) 
    .then(json => { resolve(json); }) 
    }); 
} 

async function your_function() { 
    var json = await ajax_call('www.api-example.com/some_data', 'GET'); 
    console.log(json); // { status: 200, data: ... } 
} 

底線:利用承諾的力量。