摘要:引言作為服務(wù)器的優(yōu)勢就在于適合處理高并發(fā)的請求,對于網(wǎng)站后臺這種密集型的后臺尤其有優(yōu)勢,其核心就在于是一個異步非阻塞模型。關(guān)于異步,同步,阻塞,非阻塞這些概念,本文不做討論。另外兩個的調(diào)用時間需要判斷是否都在主線程中被執(zhí)行。
引言
node作為服務(wù)器的優(yōu)勢就在于適合處理高并發(fā)的請求,對于web網(wǎng)站后臺這種I/O密集型的后臺尤其有優(yōu)勢,其核心就在于node是一個異步非阻塞模型。關(guān)于異步,同步,阻塞,非阻塞這些概念,本文不做討論。
node的單線程模型js作為單線程語言,有自己的一套運行機制
同步任務(wù)運行在主線程上,異步的所有任務(wù)都會在另一個隊列中等待執(zhí)行,一旦同步任務(wù)執(zhí)行完畢開始執(zhí)行異步隊列中的任務(wù),此時可以認(rèn)為將第一個異步隊列中的任務(wù)移到主線程,一旦再產(chǎn)生異步操作,就會繼續(xù)往異步隊列中添加,以此循環(huán)。這就是為什么promise,setTimeout,setInterval,process.nextTick,setImmediate,ajax請求,看起來雖然位于代碼的上面部分卻沒有被按順序執(zhí)行。
看一下node的eventloop的機制,也就是node實現(xiàn)異步的架構(gòu)。
主要的不同點是用LIBUV去將隊列中的任務(wù)形成一個eventloop,作為下一個循環(huán)需要執(zhí)行的工作。
觀察者模式的體現(xiàn)個人一直認(rèn)為js的異步回調(diào)是一種觀察者模式的體現(xiàn),訂閱/發(fā)布,網(wǎng)上的說法是有三種觀察者
idle觀察者:顧名思義,就是早已等在那里的觀察者,以后會說到的process.nextTick就屬于這類I/O觀察者:顧名思義,就是I/O相關(guān)觀察者,也就是I/O的回調(diào)事件,如網(wǎng)絡(luò),文件,數(shù)據(jù)庫I/O等
check觀察者:顧名思義,就是需要檢查的觀察者,后面會說到的setTimeout/setInterval就屬于這類
優(yōu)先級idle觀察者>I/O觀察者>check觀察者
詳細(xì)鏈接
但是個人看法setTimeout()和setInterval()可以歸為一類觀察者,算是timer觀察者,setImmediate()是check觀察者,至于原因后面回說明
以下是自己對setTimeout(),setImmediate()和process.nextTick()的比較
首先所有討論均是建立在node的基礎(chǔ)上,三個函數(shù)也都只比較分析node 中情況,摘自node文檔
setTimeout()callbackThe function to call when the timer elapses.
delayThe number of milliseconds to wait before calling the callback. Schedules execution of a one-time callback after delay milliseconds. Returns a Timeout for use with clearTimeout().
The callback will likely not be invoked in precisely delay milliseconds. Node.js makes no guarantees about the exact timing of when callbacks will fire, nor of their ordering. The callback will be called as close as possible to the time specified.
這里明確了兩點,一個是settimeout的實際執(zhí)行時間必然晚于設(shè)置時間,作精確定時器根本就是違背他的設(shè)計意愿的,另外一點就是他的函數(shù)回調(diào)是timer觀察的。
setImmediate()callbackThe function to call at the end of this turn of the Node.js Event Loop
...argsOptional arguments to pass when the callback is called. Schedules the "immediate" execution of the callback after I/O events" callbacks. Returns an Immediate for use with clearImmediate().
When multiple calls to setImmediate() are made, the callback functions are queued for execution in the order in which they are created. The entire callback queue is processed every event loop iteration. If an immediate timer is queued from inside an executing callback, that timer will not be triggered until the next event loop iteration.
核心,回調(diào)會被立刻放在eventLoop的末尾
process.nextTick()callback
...argsAdditional arguments to pass when invoking the callback he process.nextTick() method adds the callback to the "next tick queue". Once the current turn of the event loop turn runs to completion, all callbacks currently in the next tick queue will be called.
This is not a simple alias to setTimeout(fn, 0). It is much more efficient. It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.
文檔中自己就提到了process.nextTick()并非 setTimeout(fn, 0),他更有效率,并且執(zhí)行的序列必在下次所有的event loop的最前列。
比較之后在node文檔中有一個比較細(xì)致的比較,鏈接
比較這三個函數(shù),先說process.nextTick(),文檔中說了process.nextTick() is not technically part of the event loop,現(xiàn)在很明確了process.nextTick()并不在event loop里,他回調(diào)的執(zhí)行是在事件等待隊列之外的,算是優(yōu)先級最高的插隊人員,那它作為最優(yōu)先執(zhí)行回調(diào)的就沒有疑問了,實際的用處就是有一些必須最優(yōu)先執(zhí)行的回調(diào),比如網(wǎng)絡(luò)服務(wù)端中,端口的監(jiān)聽?wèi)?yīng)該必須早于其他事件的回調(diào)。
setImmediate() vs setTimeout()這個可能是網(wǎng)上說法最不統(tǒng)一的地方了,說誰先執(zhí)行的都有,先測了下面的代碼
setTimeout(() => { console.log("timeout"); }, 0); setImmediate(() => { console.log("immediate"); });
結(jié)果還真的是隨機的,這么不嚴(yán)謹(jǐn)?其實官方對這個是有解釋的
The order in which the timers are executed will vary depending on the context in which they are called. If both are called from within the main module, then timing will be bound by the performance of the process (which can be impacted by other applications running on the machine).
However, if you move the two calls within an I/O cycle, the immediate callback is always executed first:
這個教育了我,真理是有范圍的,所謂普遍真理是形而上學(xué)。所以說setImmediate() vs setTimeout()誰快不能簡單的說,必須先討論使用的地方。
上面有提到setTimeout(fn, 0)效率不高,至于為什么,暫時參照國內(nèi)普遍的說法 該函數(shù)的事件控制,是被維護(hù)在紅黑樹上,那么為了每次去找超時的回調(diào)必然是logn的復(fù)雜度,而另外兩個函數(shù)看起來都應(yīng)該是1的復(fù)雜度
總結(jié)綜上個人傾向于四種觀察者的說法
至于setImmediate() vs setTimeout() vs process.nextTick(),process.nextTick()最快,也有獨特的應(yīng)用場景。另外兩個的調(diào)用時間需要判斷是否都在主線程中被執(zhí)行。
setTimeout(fn, 0)效率偏低。
tip:node官方建議使用setimmediate(),因為至少應(yīng)用的范圍就可以到瀏覽器端了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/107639.html
摘要:標(biāo)準(zhǔn)庫中的所有方法都提供非阻塞的異步版本,并接受回調(diào)函數(shù),某些方法還具有對應(yīng)的阻塞方法,其名稱以結(jié)尾。比較代碼阻塞方法同步執(zhí)行,非阻塞方法異步執(zhí)行。 阻塞與非阻塞概述 此概述介紹了Node.js中阻塞與非阻塞調(diào)用之間的區(qū)別,此概述將引用事件循環(huán)和libuv,但不需要事先了解這些主題,假設(shè)讀者對JavaScript語言和Node.js回調(diào)模式有基本的了解。 I/O主要指與libuv支持的...
摘要:而線程是進(jìn)程的一部分,二者相扶相依,其中單線程被稱為輕權(quán)進(jìn)程或輕量級進(jìn)程,執(zhí)行特性線程只有個基本狀態(tài)就緒,執(zhí)行,阻塞。以上所述證明了操作與其他函數(shù)的這種區(qū)別是由實現(xiàn),是用多線程的方式,在標(biāo)準(zhǔn)的阻塞式上模擬非阻塞異步,線程池默認(rèn)限制四線程。 node - 非阻塞的異步 IO 每當(dāng)我們提起 node.js 時總會脫口而出 事件驅(qū)動、非阻塞I/O 和 單線程,所以我總結(jié)了以下幾點對這三項概念...
摘要:而線程是進(jìn)程的一部分,二者相扶相依,其中單線程被稱為輕權(quán)進(jìn)程或輕量級進(jìn)程,執(zhí)行特性線程只有個基本狀態(tài)就緒,執(zhí)行,阻塞。以上所述證明了操作與其他函數(shù)的這種區(qū)別是由實現(xiàn),是用多線程的方式,在標(biāo)準(zhǔn)的阻塞式上模擬非阻塞異步,線程池默認(rèn)限制四線程。 node - 非阻塞的異步 IO 每當(dāng)我們提起 node.js 時總會脫口而出 事件驅(qū)動、非阻塞I/O 和 單線程,所以我總結(jié)了以下幾點對這三項概念...
摘要:而線程是進(jìn)程的一部分,二者相扶相依,其中單線程被稱為輕權(quán)進(jìn)程或輕量級進(jìn)程,執(zhí)行特性線程只有個基本狀態(tài)就緒,執(zhí)行,阻塞。以上所述證明了操作與其他函數(shù)的這種區(qū)別是由實現(xiàn),是用多線程的方式,在標(biāo)準(zhǔn)的阻塞式上模擬非阻塞異步,線程池默認(rèn)限制四線程。 node - 非阻塞的異步 IO 每當(dāng)我們提起 node.js 時總會脫口而出 事件驅(qū)動、非阻塞I/O 和 單線程,所以我總結(jié)了以下幾點對這三項概念...
閱讀 3412·2021-11-25 09:43
閱讀 3257·2021-10-11 10:58
閱讀 2837·2021-09-27 13:59
閱讀 3140·2021-09-24 09:55
閱讀 2228·2019-08-30 15:52
閱讀 1893·2019-08-30 14:03
閱讀 2305·2019-08-30 11:11
閱讀 2077·2019-08-28 18:12