2012-11-13 55 views
0

我正在閱讀這篇文章,我有一個特別的疑問,如果有人明確告訴我。事件驅動的編程node.js?

http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb

var fs = require('fs') 
    , sys = require('sys'); 

fs.readFile('treasure-chamber-report.txt', function(report) { 
    sys.puts("oh, look at all my money: "+report); 
}); 

fs.writeFile('letter-to-princess.txt', '...', function() { 
    sys.puts("can't wait to hear back from her!"); 
}); 

你的代碼給出節點兩項任務讀取和寫入文件,然後進入睡眠狀態。一旦節點完成一項任務,它的回調就會被觸發。但同時只能有一次回調觸發。在該回調完成執行之前,所有其他回調都必須排隊等待。除此之外,回調的觸發順序無法保證。

「所以我不必擔心代碼在同一時間訪問相同的數據結構?」 你明白了!這就是JavaScripts單線程/事件循環設計的完美之處!

  1. 任何人都可以解釋我上面的粗線。我們怎麼會不擔心這兩個不同的程序不會訪問該對象。
  2. 目前的線程方式有什麼問題?
  3. 觸發回調的順序會成爲問題嗎?讓我們把我想callBack A()在callBack b()之前先返回。

回答

6

1)如果你正在運行單線程,你不必擔心多線程應用程序帶來的問題。這包括2個不同的線程試圖同時使用同一個對象。想象一下,例如,如果一個線程試圖從哈希中讀取數據,而另一個線程正在從同一個哈希中刪除數據。一個鍵/值對可能看起來像它存在於一行代碼中,但由於線程到達下一行的時間,數據可能不再存在。同樣,你不必處理所有額外的代碼和頭痛,避免這些問題。

2)參見#1。這不是一個問題,而是一個權衡。現在很多計算機都有多個處理器/內核,因此讓程序一次使用多個線程是有益的。當你期望一個線程被阻塞時它也很有用。例如,在另一種多線程語言中,通常閱讀文件的內容,並輸出它們而不添加回調。但是,這意味着線程在那裏無所事事(阻塞),直到文件讀取操作完成。多線程編程也很難做到正確。

3)你不會被保持秩序。如果你想確保正確的順序,你需要等待第二個呼叫,直到第一個呼叫返回。例如

fs.readFile('treasure-chamber-report.txt', function(report) { 
    sys.puts("oh, look at all my money: "+report); 

    fs.writeFile('letter-to-princess.txt', '...', function() { 
     sys.puts("can't wait to hear back from her!"); 
    }); 
}); 

注意,這有時可以讓你到什麼是通常被稱爲「回調地獄」

編輯:爲了解決您的意見:

1)即使你是「等待」爲NodeJS爲要讀取的文件,在NodeJS中這是一個非阻塞操作。這意味着即使在讀取文件之前,方法調用(readFile)也會立即返回。這是因爲它將數據IO請求傳遞給底層操作系統,底層操作系統擁有自己的線程來處理這些請求。當操作系統完成讀取(或寫入)時,它會通知發起進程它已準備好數據。當操作系統正在完成這項工作時,NodeJS可以讓一個線程在等待時繼續執行其他工作。這就是爲什麼你需要回調 - 你需要一種方法告訴NodeJS當你最終獲得數據時接下來要做什麼。

2)回調地獄沒有什麼固有的壞處,除非難以閱讀。可以想象,如果你正在嘗試做的包括幾個不同的異步進程(如讀取和寫入到磁盤),你可能會得到的東西看起來是這樣的:

var doSomething function(){ 
    fs.readFile('step1.txt', function(result){ 
     // do something with the result 
     fs.writeFile('step2.txt', function(){ 
      // okay, step2 is ready, so process that 
      fs.readFile('step2.txt', function(result){ 
       fs.writeFile('step3.txt', function(){ 
        //etc, etc 
       }); 
      }); 
     }); 
    }); 
} 

你可以看到,嵌套可以得到相當深得很快,而且難以閱讀。如果你搜索「JavaScript回調地獄」,那麼在這裏和其他地方有很多討論這個問題的討論。一種解決問題的方法是避免內聯/匿名函數,並用命名函數將其扁平化,因此回調函數在嵌套編輯器中嵌套得並不深(儘管嵌套仍然是從詞法的角度出發)。

+0

你能解釋我這個...你的第二點如何解決與nodejs ...即使我使用nodeJS我會一直等到整個文件被讀取以顯示輸出。 – theJava

+0

馬特:你可以解釋我更多的回調地獄問題,以及如何導致這個問題。 – theJava

+0

@theJava我已經更新了我的答案,希望能夠解答您的意見。 – Matt