首頁 >web前端 >js教程 >有關js事件的循環機制(詳細教學)

有關js事件的循環機制(詳細教學)

亚连
亚连原創
2018-06-21 11:06:211561瀏覽

這篇文章主要介紹了js事件循環機制,並透過實例分析了用法和技巧,一起學習分享下。

本文透過實例給大家詳細分析了JS中事件循環機制的原理和用法,以下是全部:

var start = new Date()
setTimeout(function () {
 var end = new Date
 console.log('Time elapsed:', end - start, 'ms')
}, 500)
while (new Date() - start < 1000) {
}

有其他語言能完成預期的功能嗎? Java, 在Java.util.Timer中,對於定時任務的解決方案是透過多線程手段實現的,任務物件儲存在任務佇列,由專門的調度線程,在新的子線程中完成任務的執行

js是單執行緒的

JavaScript的主要用途是與使用者互動,以及操作DOM。這決定了它只能是單線程,否則會帶來複雜的同步問題。

為了利用多核心CPU的運算能力,HTML5提出Web Worker標準,允許JavaScript腳本建立多個線程,但是子執行緒完全受主執行緒控制,且不得操作DOM。所以,這個新標準並沒有改變JavaScript單執行緒的本質。

函數呼叫堆疊與任務佇列

在呼叫堆疊

JS執行時會形成呼叫堆疊,調用一個函數時,返回地址、參數、本地變數都會被推入棧中,如果當前正在運行的函數中調用另外一個函數,則該函數相關內容也會被推入棧頂.該函數執行完畢,則會被彈出調用棧.變數也隨之彈出,由於複雜型別值存放於堆中,因此彈出的只是指針,他們的值依然在堆中,由GC決定回收.

事件循環(event loop ) & 任務佇列(task queue)

JavaScript 主執行緒擁有執行堆疊以及一個任務佇列

遇到非同步操作(例如:setTimeout, AJAX)時,非同步操作會由瀏覽器(OS)執行,瀏覽器會在這些任務完成後,將事先定義的回調函數推入主線程的任務隊列(task queue)中,當主線程的執行棧清空之後會讀取task queue中的回調函數,當task queue被讀取完畢之後,主線程接著執行,從而進入一個無限的循環,這就是事件循環.

主線程執行棧& 任務隊列循環執行,構成事件循環

結論

setTimeout()只是將事件插入了"任務佇列",必須等到目前程式碼(執行堆疊)執行完,主執行緒才會去執行它指定的回呼函數。要是當前程式碼耗時很長,有可能要等很久,所以沒有辦法保證,回呼函數一定會在setTimeout()指定的時間執行。

另一個例子

(function test() {
 setTimeout(function() {console.log(4)}, 0);
 new Promise(function executor(resolve) {
 console.log(1);
 for( var i=0 ; i<10000 ; i++ ) {
 i == 9999 && resolve();
 }
 console.log(2);
 }).then(function() {
 console.log(5);
 });
 console.log(3);
})()

Macrotask & Microtask

#macrotask 和 microtask 是非同步任務的兩種分類。在掛起任務時,JS 引擎會將所有任務依照類別分到這兩個佇列中,首先在macrotask 的佇列(這個佇列也被稱為task queue)中取出第一個任務,執行完畢後取出microtask 佇列中的所有任務順序執行;之後再取macrotask 任務,周而復始,直至兩個隊列的任務都取完。

macro-task: script(整體程式碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, Promises(這裡指瀏覽器實現的原生Promise) , Object.observe, MutationObserver

#結論

全部程式碼(script) macrotask -> microtask queue (含有promise.then ) -> macrotask(setTimeout) -> 下一個microtask

Node.js的事件循環

process.nextTick & setImmediate

process.nextTick指定的任務總是發生在所有非同步任務之前

setImmediate指定的任務總是在下一次Event Loop時執行

process.nextTick(function A() {
 console.log(1);
 process.nextTick(function B(){console.log(2);});
});
setTimeout(function timeout() {
 console.log(&#39;TIMEOUT FIRED&#39;);
}, 0)
new Promise(function(resolve) {
 console.log(&#39;glob1_promise&#39;);
 resolve();
}).then(function() {
 console.log(&#39;glob1_then&#39;)
})
process.nextTick(function() {
 console.log(&#39;glob1_nextTick&#39;);
})

上面是我整理給大家的,希望今後會對大家有幫助。

相關文章:

使用Javascript如何開發二維週視圖日曆

相關JS抽象工廠模式(詳細教學)

在Django與Vue語法中存在衝突問題如何解決

#在nodejs中如何實作爬取網站圖片

以上是有關js事件的循環機制(詳細教學)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn