網絡請求》scriptText》Parser轉義》AST》Ignition編譯》ByteCode字節碼》提取循環執行》優化編譯器
- 執行js代碼
- 解析源碼並轉成抽象語法樹(AST)
- 基於AST,Ignition解釋器產出字節碼
- 同時運行代碼並收集類型反饋
- 引擎檢測到常用行為(循環)發生,以及使用的數據類型,為了更高效,字節碼可以反饋數據一起被髮送到優化編譯器。優化編譯器會經過假設實現高度優化的機器碼【內聯緩存技術(inline cashing)】
- 如果某些時候,其中一個假設不成立,優化編輯器就會取消優化,並回到解釋器
AST
JavaScript解析器傳成AST樹:
^解析後的ast樹
從上圖中可以看出,我們只需要遍歷這個樹就能得知let關鍵字和其值。
執行上下文
一個變量提升可以看出來:
function () {
var x;
let n;
{
var l
let m
}
console.log(x,n,l)
console.log(m)
}
如果我們打印以上x,n,l,m
這時候會發現l,x,n都會打印,但m會報錯。
它們可以用以下包含形式解釋:
[var x=undefined; var l=undefiend]
[[let n[let m]]]
從上面可以看出關係是var定義的變量是在同一個區間內。而let定義的變量在同一個區間內的區域內。
var默認值為undefined,而let沒有任何默認值。
javascript在執行時候,同步任務總是自上而下執行。
異步任務需要先判斷是宏任務還是微任務。宏任務進宏任務隊列,微任務進微任務隊列。
宏任務
可以將每次執行棧執行的代碼當做是一個宏任務
- I/O
- setTimeout
- setInterval
- setlmmediate
- requestAnimationFrame
微任務
當 宏任務 執行完,會在渲染前,將執行期間所產生的所有 微任務 都執行完
- process.nextTick (nodejs)
- MutationObserver
- Promise.then catch finally
先執行宏任務的第一個。在宏觀上,因為我們把同步代碼歸為宏任務。同步任務就是第一個宏任務,但其實它沒進宏任務隊列。宏觀上講:宏任務》微任務。
好理解講:同步任務(第一個宏任務)》微任務》宏任務
事件循環:
分析:
同步任務:log(1),log(7),直接執行。因此1,7先打印;
微任務:log(3),settimeout => log(4),log(5),因此能執行的只有3,5; settimeout => log(4)被壓入宏任務棧。
宏任務:log(2),log(6),log(4)所以最後打印:2,6,4;
垃圾回收有幾個常見的算法
引用計數,缺點也非常明顯
標記清除
標記清除壓縮
Cheney 算法,是目前用在 v8 新生代垃圾回收