Nodejs中 Callback 的執行是否造成阻塞?
Node.js中的回調函數一般是指非同步操作完成之後調用的函數。
基於非同步事件模型的Node.js大致是這樣運行的:
- 向Node.js提交非同步操作,比如建立網路連接,讀取網路流數據,向文件寫入數據,請求資料庫服務等,同時針對這些非同步操作註冊回調函數。這些非同步操作會提交給IO線程池或者工作線程池。
- 在線程池中,操作是並發的執行,也就是讀網路流和向文件寫數據,或者請求資料庫服務都是並發的(可能是這樣子的,具體的操作怎麼完成,是node的事) ,執行完畢後會將就緒事件放入完成隊列中。
- 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 |