標籤:

Nodejs中 Callback 的執行是否造成阻塞?


Node.js中的回調函數一般是指非同步操作完成之後調用的函數。

基於非同步事件模型的Node.js大致是這樣運行的:

  1. 向Node.js提交非同步操作,比如建立網路連接,讀取網路流數據,向文件寫入數據,請求資料庫服務等,同時針對這些非同步操作註冊回調函數。這些非同步操作會提交給IO線程池或者工作線程池。
  2. 在線程池中,操作是並發的執行,也就是讀網路流和向文件寫數據,或者請求資料庫服務都是並發的(可能是這樣子的,具體的操作怎麼完成,是node的事) ,執行完畢後會將就緒事件放入完成隊列中。
  3. Node.js 在提交完操作請求之後,進入循環(或叫事件循環吧)。循環的過程如下:

a. 檢查有沒有計時器超時(setTimeout/setInterval)

b. 檢查當前是否為空閑狀態,執行空閑任務(process.nextTick)

c. 檢查IO完成隊列(各種網路流讀寫、文件讀寫、標準輸入輸出上的事件都會進入這個隊列)是否有就緒事件,

若完成隊列中有就緒事件,就把隊列里的所有事件(可能有多個操作已經完成)信息都取出來,對這些事件信息,挨個地調用與其相關的回調函數。這個過程是同步的,執行「寫數據完成」事件的回調函數完成之後,才會去調用「讀到網路數據」事件的回調函數;

若是隊列中沒有就緒事件,而且沒有空閑(idle)任務,就會做一段時間的等待(線程被阻塞在此處),等待的超時時間由計時器周期決定。(不能因為等待而耽誤timer和idle的事件處理)。

d. 進入下一輪循環。

從上面這個過程可以看出,你腳本中註冊的所有回調函數都是在這個循環過程中被依次調用的。若有一個回調函數執行大的計算任務,很長時間不返回的話,就會讓整個循環停頓下來,其它回調函數就不能在事件到來時即時被回調。因此,建議長任務處理過程中,即時將剩下的處理通過process.nextTick丟入下一輪循環中有idle事件中,或者process.spawn一個進程來執行。

總之,除了你的代碼是同步執行的以外,其它所有的事情都是並發的。

表述能力有限,囧。感覺自己還沒有說清楚。大概是這個樣子的。


看怎麼理解,事實上每一個function的執行本身在Javascript里都是阻塞的,區別只是阻塞時間長短而已。

但實際編程的時候有一種相對的理解,阻塞意味著長時間的等待,這當然和JS的阻塞是不同的概念。但為了方便,舉例:

app.onReady(function () {

// 執行這個函數仍然需要花少量事件,所以是阻塞的
// 但編程的時候通常認為這個回調是不阻塞的

// setTimeout本身的執行是阻塞的,但極為短暫
setTimeout(function() { ... }, 1000);
// addEventListener本身的執行也是阻塞的,但極為短暫(微妙級)
window.addEventListner("resize", function () { ... });
});

console.log(..) // 幾乎立即執行

app.onReady(function () {
document.querySelector("p"); // 阻塞
for (...) {
document.querySelector("xxx").style.... = ... // 較長時間的阻塞
}
}):

console.log(..) // 等待

這樣區別有實際的意義,因為多數時候我們希望避開(長時間)」阻塞「的代碼。


除了你的代碼是阻塞的外,其餘的都是並行非同步的。


除了帶 Sync 尾的,都沒有阻塞。


阻塞沒事,如果都不能阻塞,callback有鳥用。非同步是可以嵌套的,比如讀memcache,如果沒有再從資料庫讀取,memcache的回調中調用資料庫,當然是阻塞的。promise就是解決這個嵌套問題,用callback代碼太難看難懂。阻塞只是把當前業務掛起,nodejs會調用其他等待隊列。

這個不是操作系統層次的中斷回調,那個是不能阻塞的,因為執行程序在中斷環境中,為了防止中斷重入,有時候會關中斷,這時候阻塞是要命的。nodejs,nginx這些業務層次的非同步回調 顯然是沒有任何問題。console.log就是阻塞的,回調里用這個函數不是很常見。


Node.js中的非同步執行其實可以對照地理解成WebWorker,進入非同步處理後,是不會阻塞執行的,等計算出結果了返回,調用回調函數,回調函數中的內容是阻塞的。


代碼是阻塞的,其他非同步調用都是非阻塞的


callback是會造成阻塞,正如@曹詩蔚說的那樣,以至於node本身會限制註冊在一個事件上的回調函數的數量(默認大於10 ,參考:emitter.setMaxListeners(n))


如何防止callback阻塞的,當node隊列中的執行速度快與callback的執行速度就會阻塞


關鍵看你的callback是否寫的垃圾!

垃圾的callback就會柱塞,因為是單線程。


非阻塞是說的系統不會在調用各種IO介面時長時間等待一個IO完成。

至於你Callback阻塞不阻塞取決與你自己的應用,如果你在那兒狂用CPU算東西,那可不阻塞么。


Callback如果調用了阻塞方法,nodejs整個就都完了


node主線程不阻塞就可以了;多個阻塞的線程被放入隊列中,通過event driven,node主線程會順序的執行這個隊列;非同步並行不等於CPU執行時間上的重疊


推薦閱讀:

node.js與php相比有哪些優缺點?未來會替代php成為最好的語言嗎?
參加第11屆D2前端技術論壇,你有什麼收穫?
package-lock.json 需要寫進 .gitignore 嗎?
深JS(2015 JS中國開發者大會)有哪些女生參加?

TAG:Nodejs |