日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一文告诉你 Event Loop 是什么?

發布時間:2023/12/18 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文告诉你 Event Loop 是什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

Event Loop 也叫做“事件循環”,它其實與 JavaScript 的運行機制有關。

JS初始設計

JavaScript 在設計之初便是單線程,程序運行時,只有一個線程存在,在特定的時候只能有特定的代碼被執行。這和 JavaScript 的用途有關,它是一門瀏覽器腳本語言,通常是用來操作 DOM 的,如果是多線程,一個線程進行了刪除 DOM 操作,另一個添加 DOM,此時該如何處理?所以 JavaScript 在設計之初便是單線程的。

雖然 HTML5 增加了?Web Work?可用來另開一個線程,但是該線程仍受主線程的控制,所以 JavaScript 的本質依然是單線程

線程和進程

進程和線程是操作系統中的概念,在操作系統中,一個任務就是一個進程,比如你在電腦上打開了一個瀏覽器來觀看視頻,便是打開了一個瀏覽器進程,此時又想記錄視頻中的重要信息,于是你打開了備忘錄,這便是一個備忘錄進程,系統會為每個進程分配它所需要的地址空間,數據,代碼等系統資源。如果把一個進程看做一個小的車間,車間里有很多工人,有的負責操作機器,有的負責搬運材料,每個工人可以看做一個線程,線程可以共享進程的資源。可以說,線程是進程的最小單位,一個進程可以包含多個線程。

執行棧和任務隊列

單線程的 JavaScript 一段一段地執行,前面的執行完了,再執行后面的,試想一個,如果前一個任務需要執行很久,比如接口請求、I/O 操作,此時后面的任務只能干巴巴地等待么?干等不僅浪費了資源,而且頁面的交互程度也很差。JavaScript 意識到了這個問題,他們將任務分成了同步任務和異步任務,對于二者有不同的處理。

JavaScript 在運行時會將變量存放在堆(heap)和棧(stack)中,堆中通常存放著一些對象,而變量及對象的指針則存放在棧中。JavaScript 在執行時,同步任務會排好隊,在主線程上按照順序執行,前面的執行完了再執行后面的,排隊的地方叫執行棧(execution context stack)。JavaScript 對異步任務不會停下來等待,而是將其掛起,繼續執行執行棧中的同步任務,當異步任務有返回結果時,異步任務會加入與執行棧不一樣的隊列,即任務隊列(task queue),所以任務隊列中存放的是異步任務執行完成后的結果,通常是回調函數。

當執行棧的同步任務已經執行完成,此時主線程閑下來,它便會去查看任務隊列是否有任務,如果有,主線程會將最先進入任務隊列的任務加入到執行棧中執行,執行棧中的任務執行完了之后,主線程便又去任務隊列中查看是否有任務可執行。主線程去任務隊列讀取任務到執行棧中去執行,這個過程是循環往復的,這便是?Event Loop,事件循環。

網上有張流傳甚廣的圖對這一過程進行了總結,在圖中我們可以看到,JavaScript 在運行時產生了堆和棧,ajax、setTimeout 等異步任務被掛起,異步任務的返回結果加入任務隊列,主線程會循環往復地讀取任務隊列中的任務,加入執行棧中執行。

?

(JavaScript 運行機制,圖片來源于網絡)

宏任務與微任務

異步任務有更深一層的劃分,它們是宏任務(macro task)和微任務(micro task),二者的執行順序也有差別。在上面我們講到異步任務的結果會進入任務隊列中,對于不同的事件類型,宏任務會加入宏任務隊列,微任務會加入微任務隊列。在執行棧中的同步任務執行完成后,主線程會先查看任務隊列中的微任務,如果有沒有,則去宏任務隊列中取出最前面的一個事件加入執行棧中執行;如果有,則將所有在微任務隊列中的事件依次加入執行棧中執行,直到所有事件執行完成后,再去宏任務中取出最前面的一個事件加入執行棧,如此循環往復。

由此我們可以得出結論,主線程總是會先查看微任務隊列,等到微任務隊列中的事件都處理完成后,再去宏任務隊列中添加一個事件到任務棧中執行。

常見的宏任務有 setTimeout,setInterval;常見的微任務有 new Promise。

代碼例子體驗

console.log(1)setTimeout(function() {console.log(2)new Promise(function(resolve) {console.log(3)resolve(4)}).then(function(num) {console.log(num)}) }, 300)new Promise(function(resolve) {console.log(5)resolve(6) }).then(function(num) {console.log(num) })setTimeout(function() {console.log(7) }, 400)

我們一步步來分析上面的執行順序,當程序開始執行時,首先打印出 1,然后遇到了 setTimeout,主程序將它掛起,300 毫秒后它的回調函數進入宏任務隊列,我們記做 setTimeout1。隨后遇到了 new Promise,resolve 部分是同步執行的,所以會打印出 5,then 中的回調函數進入微任務隊列,我們暫時記做 promise1。最后是 setTimeout,同理在 400 毫秒后加入了宏任務隊列,我們記做 setTimeout2。

此時任務隊列的情況如下:

宏任務

微任務

setTimeout1

promise1

setTimeout2

?

執行棧中的同步任務執行完成后,主線程查看任務隊列時發現存在微任務,于是把 promise1 執行了,打印出 6。此時微任務隊列已經空了,于是開始查看宏任務隊列,將 setTimeout1 的回調函數加入任務棧開始執行,于是首先打印出 2,之后是 3,再將 then 中的回調函數加入微任務隊列,我們記做 promise2。

此時任務隊列的情況如下:

宏任務

微任務

setTimeout2

promise2

此時執行棧也空了,于是將微任務 promise2 加入執行棧,打印出 4。此時微任務已經執行完,再查看宏任務隊列,于是執行 setTimeout2,打印出 7。

所以代碼中的輸出順序是 1,5,6,2,3,4,7。

注意,主線程對微任務的讀取是逐個讀取,直到微任務隊列為空,再讀取宏隊列,對宏任務隊列的讀取在一個循環中只讀取一個。

小結

我們了解了 JavaScript 的運行機制,它是單線程的。JavaScript 中的任務可分為同步任務和異步任務,同步任務總是先進入執行棧中執行,異步任務會被掛起,直到有結果返回時,異步任務會進入任務隊列中等待主線程讀取執行。當執行棧為空時,主線程便會循環往復地讀取任務隊列中的事件,進入執行棧執行,這個過程叫 Event Loop。主線程對任務隊列的讀取也有先后之分,首先會去查找微任務,微任務隊列的事件都執行完畢后,再讀取最前面的宏任務進行執行,執行完再讀取微任務隊列,這個過程也是循環往復的。

?

轉載于:https://www.cnblogs.com/Joe-and-Joan/p/10687551.html

總結

以上是生活随笔為你收集整理的一文告诉你 Event Loop 是什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。