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

- 堆記錄了內(nèi)存的分配
- 調(diào)用棧是棧幀這類東西所在的地方
setTimeout或者DOM,HTTP請(qǐng)求這些東西并不存在于V8引擎中
那我們?nèi)绾芜M(jìn)行異步編程呢?

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

- 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

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

錯(cuò)誤是從foo開始,到bar,到baz,再到匿名函數(shù),也就是上圖中的main函數(shù)
內(nèi)存泄露
如果我們有一個(gè)調(diào)用自身的函數(shù)foo,那么會(huì)發(fā)生什么呢?

阻塞
沒有什么嚴(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)圖加深理解

事件循環(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é)束