Event Loop

javascript 運(yùn)行時(shí)

image.png
  • 堆記錄了內(nèi)存的分配
  • 調(diào)用棧是棧幀這類東西所在的地方

setTimeout或者DOM,HTTP請(qǐng)求這些東西并不存在于V8引擎中
那我們?nèi)绾芜M(jìn)行異步編程呢?

image.png
  • 上圖中包含了V8運(yùn)行環(huán)境
  • 然后是瀏覽器提供的其它部分WebAPIs(DOM,AJAX,setTimeout)
  • 再然后就是事件循環(huán)event loop 和 回調(diào)隊(duì)列 call back queue

單線程

image.png
  • javascript是一個(gè)單線程的編程語言
  • 單線程的運(yùn)行環(huán)境,它有且只有一個(gè)調(diào)用棧,它每次只能夠做一件事情

call stack 調(diào)用棧

什么是調(diào)用棧
記錄當(dāng)前程序所在位置的數(shù)據(jù)結(jié)構(gòu)

  • 如果當(dāng)前進(jìn)入了某個(gè)函數(shù),v8就創(chuàng)建一個(gè)棧幀壓入棧中
  • 如果當(dāng)前離開了某個(gè)函數(shù),該棧幀就會(huì)被彈出棧外

你可以借助如下動(dòng)圖理解call stack

166b35374a9a1833.gif

當(dāng)我們?cè)贑hrome的控制臺(tái)上運(yùn)行如下代碼時(shí),會(huì)拋出一個(gè)異常,它將整個(gè)棧樹都打印了出來

image.png

錯(cuò)誤是從foo開始,到bar,到baz,再到匿名函數(shù),也就是上圖中的main函數(shù)

內(nèi)存泄露

如果我們有一個(gè)調(diào)用自身的函數(shù)foo,那么會(huì)發(fā)生什么呢?

111.gif

阻塞

沒有什么嚴(yán)格意義上的阻塞,阻塞僅僅指的是代碼運(yùn)行很慢,比如說

  • console.log不慢,但是遍歷從1到10億很慢
  • http請(qǐng)求很慢
  • 加載圖片很慢

反正在調(diào)用棧里表現(xiàn)很慢的東西都叫阻塞

同步任務(wù)和異步任務(wù)

javascript程序中任務(wù)可以分為兩類

  • 1 同步任務(wù)
  • 2 異步任務(wù)

同步任務(wù)會(huì)依次進(jìn)入call stack調(diào)用棧中執(zhí)行
異步任務(wù)會(huì)被v8引擎放入 任務(wù)隊(duì)列中,只有當(dāng)同步任務(wù)全部執(zhí)行完畢,異步任務(wù)才會(huì)從隊(duì)列首部至尾部依次進(jìn)入調(diào)用棧執(zhí)行

任務(wù)隊(duì)列和事件循環(huán)

V8引擎提供了兩個(gè)東西

  • 1一個(gè)正在運(yùn)行的主線程
  • 2 task queue 任務(wù)隊(duì)列(用于存放程序中的異步任務(wù))
    • 每一個(gè)異步任務(wù)都有一個(gè)為了處理這個(gè)異步任務(wù)相關(guān)聯(lián)的函數(shù)
  • 1 主線程會(huì)去執(zhí)行所有的同步任務(wù)。
  • 2 等到同步任務(wù)全部執(zhí)行完,就會(huì)去看任務(wù)隊(duì)列里面的異步任務(wù)。
  • 3 如果滿足條件,那么異步任務(wù)就重新進(jìn)入主線程開始執(zhí)行,這時(shí)它就變成同步任務(wù)了。
  • 4 等到執(zhí)行完,下一個(gè)異步任務(wù)再進(jìn)入主線程開始執(zhí)行。一旦任務(wù)隊(duì)列清空,程序就結(jié)束執(zhí)行

通過下面動(dòng)圖加深理解


222.gif

事件循環(huán)

異步任務(wù)的寫法通常是回調(diào)函數(shù)s。一旦異步任務(wù)重新進(jìn)入主線程,就會(huì)執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。如果一個(gè)異步任務(wù)沒有回調(diào)函數(shù),就不會(huì)進(jìn)入任務(wù)隊(duì)列,也就是說,不會(huì)重新進(jìn)入主線程,因?yàn)闆]有用回調(diào)函數(shù)指定下一步的操作。

javaScript 引擎怎么知道異步任務(wù)有沒有結(jié)果,能不能進(jìn)入主線程呢?答案就是引擎在不停地檢查,一遍又一遍,只要同步任務(wù)執(zhí)行完了,引擎就會(huì)去檢查那些掛起來的異步任務(wù),是不是可以進(jìn)入主線程了。這種循環(huán)檢查的機(jī)制,就叫做事件循環(huán)(Event Loop)

總結(jié)
V8引擎主要做了哪些事情
1 將異步任務(wù)掛起,
2 主線程依次執(zhí)行同步任務(wù)
3 執(zhí)行同步任務(wù)的同時(shí),事件循環(huán)(event loop)定時(shí)查看異步任務(wù)的結(jié)果,符合條件的異步任務(wù)放入到任務(wù)隊(duì)列中
4 程序中所有同步任務(wù)執(zhí)行完畢后,主線程按照隊(duì)列先進(jìn)先出的特點(diǎn),總是從最先進(jìn)入隊(duì)列的一個(gè)任務(wù)開始處理
5 每一個(gè)任務(wù)都有一個(gè)與之相關(guān)的處理函數(shù),只有當(dāng)這個(gè)函數(shù)完全執(zhí)行完后,才能處理下一個(gè)任務(wù)
6 當(dāng)所有異步任務(wù)執(zhí)行完畢之后,程序結(jié)束

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容