2010-05-20 113 views
21

如何創建一個非阻塞異步函數?下面是我想要實現,但我的程序仍在攔截...如何在node.js中創建一個非阻塞異步函數?

var sys = require("sys"); 

function doSomething() { 
    sys.puts("why does this block?"); 
    while(true); 
} 

setTimeout(doSomething,0); 
setTimeout(doSomething,0); 
setTimeout(doSomething,0); 

sys.puts("main"); 

回答

3

setTimeout不會創建一個新線程,因此瀏覽器仍然掛在無限循環。

您需要重新考慮您的程序結構。

+0

你知道我在node.js中如何實現這個功能嗎?謝謝 – Richard 2010-05-20 21:37:58

+1

這個問題很老舊,但對於像我這樣的node.js初學者來說,仍然非常有趣。如前所述,node.js是針對並行I/O而非並行工作的。這意味着:如果你有一個耗時的工作來響應單個請求node.js不會加快你在單個請求中嘗試實現的內容。 使用sleep()和setTimeout()之間的區別在於,當使用sleep()進行睡眠時,node.js將阻止所有其他請求 - 使用setTimeout()將不會阻止其他請求。或者:10個睡眠請求(10s)將需要100s - 10個請求setTimeout(10s)只需10s。 – schlicki 2016-03-04 19:49:54

10

您需要在單獨的進程中運行阻塞函數。

該模塊可以幫助:http://github.com/cramforce/node-worker

+26

重要的是要明白,節點並不是一直處於異步的函數。它關於* i/o *是異步和非阻塞的。如果你的函數沒有做任何i/o,節點不會幫你使它異步。它提供的工具可以讓你做到這一點。像子進程一樣。這就是費利克斯的答案。你的函數可以派生一個子進程來完成你的工作,它將在主事件循環中執行。 – Marco 2010-05-22 14:23:04

-6

這條線:

while(true); 

不是 「堵」,它只是忙,直到永遠。

4

如果您不想使用WebWorker API/node-worker(仍然非常簡單),只需創建其他節點程序並通過TCP或HTTP進行通信即可。

這使您可以將工作分配爲HTTP調用或原始TCP數據,並異步等待HTTP響應/傳入TCP答案。

但是請注意,只有在您的任務很容易序列化時才適用。

11

通過使用由C++編寫的node.js運行時或node.js擴展提供的異步IO函數,您只能在node.js中執行異步IO。您自己的Javascript代碼在node.js中始終是同步的。異步非IO代碼很少需要,而node.js設計者決定完全避免它。

在其他評論者提到的node.js中有一些異步運行Javascript的方法,但是node.js並不是爲這類工作設計的。如果你需要這種類型的併發性,使用Erlang,node.js只是關於並行IO,而對於並行計算,它與Python或PHP一樣糟糕。

+0

很好的回答,我有一個問題:Node.js中的mongo db操作是異步IO嗎? – 2014-12-30 09:37:40

+1

是的。例如'.connect'和'.insert'是異步函數。見http://mongodb.github.io/node-mongodb-native/2.0/overview/quickstart/ – nponeccop 2014-12-30 18:15:07

31

交叉從Reddit發佈。


JavaScript中異步函數的用途與您尋求的有點不同。

請記住,JavaScript是單線程的 - 它一次只能做一件事。下面是一些傳統的,阻塞代碼:

sys.puts("Before"); 
sleep(10); 
sys.puts("After"); 

在真實世界中的Web應用程序中,sleep()可能反而是一個耗時的數據庫調用,網絡請求(如從用戶的Web瀏覽器等待數據),幫手工具或文件訪問。

如果您使用類似上述的阻塞調用,則Node.js服務器在等待時無法執行其他任何操作(如開始處理其他Web請求)。

PHP和許多其他Web編程環境通過爲每個請求創建完全獨立的線程來處理此問題。 Node.js使用回調函數。你可以寫相同的代碼是這樣,而是:

sys.puts("Before"); 
setTimeout(function(){ 
    sys.puts("After"); 
}, 10000); 

在這裏,你創建一個函數,並把它傳遞給setTimeout()。它的代碼還沒有運行,但是當它運行時,它將訪問它創建的所有範圍(所有變量)。 setTimeout()獲取對該功能的引用,並在超時到期後安排要在the event loop上觸發的事件。

事件循環本質上是一個Node.js程序的待辦事項列表(它們很常見 - 您的計算機上運行的所有GUI應用程序都可能使用事件循環!)。

呼叫setTimeout()後,當前函數繼續執行。它最終返回,並調用它的函數返回,等等,直到程序結束回事件循環。事件循環查看代碼執行時是否發生任何事情(例如傳入請求),並在代碼中調用相應的函數。如果沒有,則等待發生(如超時到期)。

異步代碼讓你的代碼在同一時間做很多事情,它消除當一些代碼依賴於外在的東西繼續阻止。

很少有您需要在Node.js程序中阻止工作。如果你這樣做了,你應該把這個工作分解成一個單獨的進程(甚至可以是另一個Node.js程序),或者編寫可以自由使用線程的a C/C++ addon

+1

啊!現在我更清楚地理解它了。感謝您的解釋;你的倒數第三段特別有用。 +1 – 2011-11-04 20:28:44

2

如果我明白你在做什麼之後,你有兩個函數(都以回調爲參數):

process.nextTick:這個函數可以堆疊,這意味着如果它被遞歸地調用,它會l在事件循環的每個節拍中輸入一個巨大的(process.maxTickDepth)次數。

setImmediate:該功能是更接近設定0超時(但發生前)。

在大多數情況下,您應該更喜歡setImmediate。

0

我假設你正在試驗Nodejs我也假設你沒有寫任何npm模塊本身並將你的函數導出爲異步函數,在實際中你不會遇到這種情況,如果你想做任何阻塞操作在單線程環境中執行的函數或回調函數中,嘗試使用適當的節點模塊(如fs進行文件讀取,請求網絡請求以及提供各種類型異步操作的異步模塊),還要記住您正在嘗試執行cpu消耗代碼異步這是一個壞主意,因爲2HZ可以在少於幾微秒內執行一百萬行代碼

nodejs的主要目的是解決您在問題中詢問的問題,即由底層libuv來處理異步事件,我很欣賞使用set time的答案,但是你不知道等待或使用node worker的時間是多少,但你最終會寫很多的boiler plate代碼,所以只需搜索可滿足您需求的npm模塊即可。

相關問題