1. 程式人生 > >Javascript事件迴圈——Event loop

Javascript事件迴圈——Event loop

引言

Javascript是一門單執行緒的指令碼語言,無法進行多執行緒程式設計; 因此為了不阻塞程式設計,Javascript通過事件迴圈的方式解決耗時任務,實現類多執行緒程式設計;

單執行緒

單執行緒意味著在瀏覽器中,同一時間只能做一件事,其他的行為和事件都會在事件佇列中排隊;

Javascript單執行緒的特性與其用途有關;作為瀏覽器指令碼語言,我們需要進行各種DOM操作,如果Javascript是多執行緒的,當兩個執行緒同時操作同一DOM,一個向其新增事件,一個要刪除此節點,瀏覽器該以哪個執行緒為準呢。

HTML5 webworker技術,允許Javascript指令碼建立多個執行緒,但子執行緒完全受主執行緒控制,且不得操作DOM,未能改變其單執行緒的本質。

執行環境 Execution Context

每當程式的執行流入到一個可執行的程式碼區塊時,就進入到一個執行環境中;

當Javascript被瀏覽器載入後,預設最先進入的是全域性執行函式,之後,函式的每次呼叫都會新建執行環境;

執行環境棧 Execution stack

執行流依次進入的執行環境在邏輯上形成一個棧,棧的底部總是全域性執行環境;棧的頂部是處於活動狀態的當前的執行環境;

每個函式都有自己的執行環境,當執行流進入一個函式時,函式的環境會被推入一個環境棧中,函式執行完成後,棧將其環境彈出,把控制權還給之前的執行環境;

注意每次函式呼叫都會建立一個執行環境壓入棧中,無論是函式內部的函式還是遞迴;

在這裡插入圖片描述

事件迴圈

執行機制

  1. 事件迴圈器會檢查事件佇列是否為空,如果為空,繼續檢查;不為空,執行2;
  2. 取出事件佇列的首項,壓入執行棧;
  3. 執行執行棧;
  4. 檢查執行棧是否為空,如果為空,執行1;不為空,繼續檢查;

macro task與micro task

非同步任務被分成兩類微任務(micro task)和巨集任務(macro task);

macro task:
script 指一開始執行的 <script> 標籤
setTimeout();
setInterval();
setImmediate()
I/O
互動事件

micro task:
new Promise();
new MutaionObserver();

同一事件迴圈中,微任務的執行優先順序高於巨集任務,只有當微任務為空後,才會去巨集任務的執行佇列中取出最前面的一個事件,壓入執行棧

注意事項

  1. 非同步程式是一個一個獨立的任務,這些任務包括:setTimeout、setInterval、ajax、eventListener等
  2. 事件佇列嚴格按照時間先後順序將任務壓入執行棧中;
  3. 當執行棧為空時,瀏覽器會一直不停的檢查事件佇列,如果不為空,則取出第一個任務;
  4. 在每一個任務結束後,瀏覽器會對頁面進行渲染;保障使用者瀏覽頁面時不會出現頁面阻塞的可能;
  5. 當執行棧為空時,便生成一個microtask檢查點;
  6. 微任務的執行優先順序高於巨集任務;

擴充套件

記憶體區域 堆(heap)和棧(stack)

Javascript執行程式碼時會將不同的變數存於記憶體中不同的位置:堆(heap)和棧(stack),堆中存放一些基礎型別的變數以及物件的指標,棧中存放著一些基礎型別的變數以及物件的指標;

每個執行緒分配一個stack,每個程序分配一個heap,stack是執行緒獨佔的,heap是執行緒共用的。stack建立時,大小確定,資料超過這個大小,會發生stack overflow錯誤;heap大小不確定,需要的話可以不斷增加;

資料存放的規則是:只要是區域性的,佔用空間確定的資料,一般放在statck,否則放在heap裡面;

stack資料在任務結束後就會銷燬; heap中的資料的銷燬依賴垃圾清理機制;一般記憶體洩漏發生在heap,即某些記憶體不再使用,卻因為種種原因,沒有被系統回收;

參考文章