摘要:引言作為服務器的優勢就在于適合處理高并發的請求,對于網站后臺這種密集型的后臺尤其有優勢,其核心就在于是一個異步非阻塞模型。關于異步,同步,阻塞,非阻塞這些概念,本文不做討論。另外兩個的調用時間需要判斷是否都在主線程中被執行。
引言
node作為服務器的優勢就在于適合處理高并發的請求,對于web網站后臺這種I/O密集型的后臺尤其有優勢,其核心就在于node是一個異步非阻塞模型。關于異步,同步,阻塞,非阻塞這些概念,本文不做討論。
node的單線程模型js作為單線程語言,有自己的一套運行機制
同步任務運行在主線程上,異步的所有任務都會在另一個隊列中等待執行,一旦同步任務執行完畢開始執行異步隊列中的任務,此時可以認為將第一個異步隊列中的任務移到主線程,一旦再產生異步操作,就會繼續往異步隊列中添加,以此循環。這就是為什么promise,setTimeout,setInterval,process.nextTick,setImmediate,ajax請求,看起來雖然位于代碼的上面部分卻沒有被按順序執行。
看一下node的eventloop的機制,也就是node實現異步的架構。
主要的不同點是用LIBUV去將隊列中的任務形成一個eventloop,作為下一個循環需要執行的工作。
觀察者模式的體現個人一直認為js的異步回調是一種觀察者模式的體現,訂閱/發布,網上的說法是有三種觀察者
idle觀察者:顧名思義,就是早已等在那里的觀察者,以后會說到的process.nextTick就屬于這類I/O觀察者:顧名思義,就是I/O相關觀察者,也就是I/O的回調事件,如網絡,文件,數據庫I/O等
check觀察者:顧名思義,就是需要檢查的觀察者,后面會說到的setTimeout/setInterval就屬于這類
優先級idle觀察者>I/O觀察者>check觀察者
詳細鏈接
但是個人看法setTimeout()和setInterval()可以歸為一類觀察者,算是timer觀察者,setImmediate()是check觀察者,至于原因后面回說明
以下是自己對setTimeout(),setImmediate()和process.nextTick()的比較
首先所有討論均是建立在node的基礎上,三個函數也都只比較分析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的實際執行時間必然晚于設置時間,作精確定時器根本就是違背他的設計意愿的,另外一點就是他的函數回調是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.
核心,回調會被立刻放在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),他更有效率,并且執行的序列必在下次所有的event loop的最前列。
比較之后在node文檔中有一個比較細致的比較,鏈接
比較這三個函數,先說process.nextTick(),文檔中說了process.nextTick() is not technically part of the event loop,現在很明確了process.nextTick()并不在event loop里,他回調的執行是在事件等待隊列之外的,算是優先級最高的插隊人員,那它作為最優先執行回調的就沒有疑問了,實際的用處就是有一些必須最優先執行的回調,比如網絡服務端中,端口的監聽應該必須早于其他事件的回調。
setImmediate() vs setTimeout()這個可能是網上說法最不統一的地方了,說誰先執行的都有,先測了下面的代碼
setTimeout(() => { console.log("timeout"); }, 0); setImmediate(() => { console.log("immediate"); });
結果還真的是隨機的,這么不嚴謹?其實官方對這個是有解釋的
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:
這個教育了我,真理是有范圍的,所謂普遍真理是形而上學。所以說setImmediate() vs setTimeout()誰快不能簡單的說,必須先討論使用的地方。
上面有提到setTimeout(fn, 0)效率不高,至于為什么,暫時參照國內普遍的說法 該函數的事件控制,是被維護在紅黑樹上,那么為了每次去找超時的回調必然是logn的復雜度,而另外兩個函數看起來都應該是1的復雜度
總結綜上個人傾向于四種觀察者的說法
至于setImmediate() vs setTimeout() vs process.nextTick(),process.nextTick()最快,也有獨特的應用場景。另外兩個的調用時間需要判斷是否都在主線程中被執行。
setTimeout(fn, 0)效率偏低。
tip:node官方建議使用setimmediate(),因為至少應用的范圍就可以到瀏覽器端了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107639.html
摘要:標準庫中的所有方法都提供非阻塞的異步版本,并接受回調函數,某些方法還具有對應的阻塞方法,其名稱以結尾。比較代碼阻塞方法同步執行,非阻塞方法異步執行。 阻塞與非阻塞概述 此概述介紹了Node.js中阻塞與非阻塞調用之間的區別,此概述將引用事件循環和libuv,但不需要事先了解這些主題,假設讀者對JavaScript語言和Node.js回調模式有基本的了解。 I/O主要指與libuv支持的...
摘要:而線程是進程的一部分,二者相扶相依,其中單線程被稱為輕權進程或輕量級進程,執行特性線程只有個基本狀態就緒,執行,阻塞。以上所述證明了操作與其他函數的這種區別是由實現,是用多線程的方式,在標準的阻塞式上模擬非阻塞異步,線程池默認限制四線程。 node - 非阻塞的異步 IO 每當我們提起 node.js 時總會脫口而出 事件驅動、非阻塞I/O 和 單線程,所以我總結了以下幾點對這三項概念...
摘要:而線程是進程的一部分,二者相扶相依,其中單線程被稱為輕權進程或輕量級進程,執行特性線程只有個基本狀態就緒,執行,阻塞。以上所述證明了操作與其他函數的這種區別是由實現,是用多線程的方式,在標準的阻塞式上模擬非阻塞異步,線程池默認限制四線程。 node - 非阻塞的異步 IO 每當我們提起 node.js 時總會脫口而出 事件驅動、非阻塞I/O 和 單線程,所以我總結了以下幾點對這三項概念...
摘要:而線程是進程的一部分,二者相扶相依,其中單線程被稱為輕權進程或輕量級進程,執行特性線程只有個基本狀態就緒,執行,阻塞。以上所述證明了操作與其他函數的這種區別是由實現,是用多線程的方式,在標準的阻塞式上模擬非阻塞異步,線程池默認限制四線程。 node - 非阻塞的異步 IO 每當我們提起 node.js 時總會脫口而出 事件驅動、非阻塞I/O 和 單線程,所以我總結了以下幾點對這三項概念...
閱讀 3346·2021-11-25 09:43
閱讀 3134·2021-10-11 10:58
閱讀 2735·2021-09-27 13:59
閱讀 3074·2021-09-24 09:55
閱讀 2166·2019-08-30 15:52
閱讀 1826·2019-08-30 14:03
閱讀 2256·2019-08-30 11:11
閱讀 2020·2019-08-28 18:12