2012-03-27 52 views
0

編輯:我們可以關閉。 Isn't truly asynchronous, non-blocking javascript impossible?Node.js是否真的異步執行後臺I/O任務?


var PATH = require ("path"); 
var URL = require ("url"); 

var sleep = function (ms){ 
    var start = new Date().getTime(); 
    while ((new Date().getTime() - start) < ms); 
} 

require ("http").createServer (function (req, res){ 
    if (URL.parse (req.url).pathname === "/1"){ 
     console.log ("tab 1: I'm in"); 
     PATH.exists ("test", function (exists){ 

      sleep (5000); 

      res.writeHead (200, {"Content-Type": "text/plain"}); 
      res.end ("1"); 
      console.log ("tab 1: I'm done"); 
     }); 
    }else{ 
     console.log ("tab 2: I'm in"); 
     res.writeHead (200, {"Content-Type": "text/plain"}); 
     res.end ("2"); 
     console.log ("tab 2: I'm done"); 
    } 
}).listen (80); 
  1. 複製內容到一個文件中。
  2. 執行該文件。
  3. 在瀏覽器中打開一個新選項卡。將url設置爲localhost/1。不要走了。
  4. 在瀏覽器中打開一個新選項卡。將網址設置爲localhost/2。不要走了。
  5. 回到第一個選項卡。按下回車鍵並在切換到第二個選項卡後立即按下回車鍵。

結果:

  • 控制檯日誌:

    標籤1:我在
    標籤1:我做
    標籤2:我在
    標籤2:我完成

  • 選項卡1等待5秒鐘以接收結果「1」。

  • 選項卡2還必須等待5秒,因爲選項卡1正在休眠5秒鐘。

該文檔說,除代碼外,所有代碼都是異步的。只有一個線程。一次只有一個請求。請求被排隊。

I/O調用應該是異步的,對嗎?那爲什麼如果回調來自異步I/O進程,爲什麼選項卡2必須等待選項卡1?

謝謝。

+1

在節點中有一個虛假的「睡眠」方法是* ragequit * – jAndy 2012-03-27 20:20:34

回答

5

因爲您的sleep正在阻止事件循環。

將其替換爲setTimemout(function() { /* Code to run */ }, 5000);,手錶/2立即作出響應。

實際的I/O是異步的,但是您在I/O上執行的所有操作都發生在事件循環中。如果有什麼東西阻塞了事件循環,那麼其他所有事情都必須等待,就像你說的。

編輯。爲更清楚起見,請看下面的ASCII圖形:

Event Loop Thread: ------+req1HandlerExistsCall+-------+req1Wait5Sec++++++++++++++++++++++++++req2ExistsCall+-------+req2Immediate+------------- 
     HTTP I/O: -+req1+--------------------------------------+req2+--------------------------------------+req1Response+--------+req2Response+ 
     File I/O: ----------------------------+exists1+----------------------------------------------------+exists2+--------------------------- 

基本上,每個線程一次只有一個。由於第一個請求處理程序阻塞了5秒(並且在速度測試中用手指擊打文件系統本質上是不可能的),所以第二個響應甚至在第一個請求差不多完成時纔開始處理。

+0

然後,exists()函數是否是同義的?那爲什麼有2個函數來測試一個文件是否存在? (exists()和existsSync())。謝謝 – 2012-03-27 20:34:59

+0

不,''存在''是異步的,但每個事件都是在一個線程上線性執行的,所以你的''sleep''命令會阻塞所有動作5秒。讓我用ASCII圖形編輯我的帖子以更好地解釋。 – 2012-03-27 21:12:51

+0

謝謝,我真的很混淆異步和併發。現在我看到node.js與傳統瀏覽器事件循環(超時,ajax等)的工作方式相同。 – 2012-03-27 21:33:21

2
  1. 您沒有任何I/O調用代碼
  2. 要調用代碼中的一個繁忙的睡眠方法,即你的代碼是用5秒鐘時間來處理。雖然它正在處理沒有別的東西可以運行在那個實例

老實說,這是一個真正的問題,或者你只是試圖打擊節點?

+0

這個問題與其他大多數問題一樣真實。 – 2012-03-27 20:32:11

+0

你一定是超級聰明的。請刪除downvote。這是一個真正的問題。 – 2012-03-27 20:46:30

1

睡眠以阻塞的方式實現,並運行在單線程的引擎上。

SetTimeout方法是在JavaScript中等待一段時間的等效版本。

還要考慮到,在JavaScript中,大部分事情都應該使用resultHandler作爲延續,並在函數完成時使用函數類型化參數處理其他函數。