js執行過程你了解多少? - 重慶崽兒brand的個人主頁www.brandhuang.com
js是單執行緒語言:
在瀏覽器中只有乙個執行緒在執行js指令碼**。雖然js是單執行緒,但在js執行過程中並不是只有乙個執行緒。其實有四個執行緒,包括:「js引擎執行緒」、「事件觸發執行緒」、「定時器觸發執行緒」、「http非同步請求執行緒」,但永遠只有「js引擎執行緒」在執行js指令碼,其他三個只是協助,不參與指令碼解析和執行。
js是單執行緒,但是**確是非同步執行的
通過事件迴圈(event loop
)的方式實現。
js引擎執行分三個階段
注:瀏覽器首先按順序載入由
標籤分割的js**塊,載入js**塊完畢後,立刻進入以下三個階段,然後再按順序查詢下乙個**塊,再繼續執行以下三個階段,無論是外部指令碼檔案(不非同步載入)還是內部指令碼**塊,都是一樣的原理,並且都在同乙個全域性作用域中。
語法分析
預編譯階段
執行階段
分析指令碼**塊語法是否正確,正確則進入「預編譯階段」,否則丟擲syntaxerror
, 停止該**塊**繼續執行,然後繼續查詢下乙個**塊。
js的執行環境(執行上下文)主要有三種: - 全域性環境(js**載入完畢後,進入預編譯階段即進入了全域性環境) - 函式環境(函式執行時進入該函式環境,不同函式的函式環境不同) - eval環境(不建議使用,會有安全,效能等問題)
執行棧,又稱呼叫棧,用來存貯**執行期間建立的所有執行上下文。是乙個遵循後進先出(lifo)的結構。棧底永遠是全域性執行上下文,棧頂是當前執行上下文。
執行上下文分兩個階段建立:1)建立執行上下文; 2)執行階段
建立變數物件
建立作用域鏈
確定this
指向
主要過程如下:
建立augments
物件:檢查當前上下文中的引數,建立物件的屬性與值,僅在函式環境(非箭頭函式?)執行,全域性環境沒有這個過程。
檢查funchtion
函式宣告,建立屬性:按**順序查詢,將找到的函式提前宣告,若函式不存在則新建立屬性和屬性值(指向該函式記憶體位址的引用);若存在,則直接覆蓋原來的。
檢查var
變數,宣告建立屬性:按**順序查詢,將找到的變數提前宣告,如果變數不存在,則賦值為:undefined
。若存在,則忽略該宣告。
注:在全域性環境中,所以函式宣告提前和變數宣告提公升是在建立變數物件中進行的,且函式宣告優先順序高於變數宣告。window
物件就是全域性執行上下文的變數物件,所有的變數和函式都是window
物件的屬性方法。
變數提公升:在建立階段,函式宣告儲存在環境中,而變數會被設定為undefined
(在var
的情況下)或保持未初始化(在let
和const
的情況下)。所以這就是為什麼可以在宣告之前訪問var
定義的變數(儘管是undefined
),但如果在宣告之前訪問let
和const
定義的變數就會提示引用錯誤的原因。
「變數物件」轉化為「活動物件」後才能進行訪問
作用域鏈由當前執行環境的變數物件和上層的一系列活動物件組成,保證了當前執行環境對符合訪問許可權的變數和函式的有序訪問。
例:
var num = 30;
function test()
innertest()
}test()
在上面的例子中,當執行到呼叫innertest
函式,進入innertest
函式環境。全域性執行上下文和test
函式執行上下文已進入執行階段,innertest
函式執行上下文在預編譯階段建立變數物件,所以他們的活動物件和變數物件分別是ao(global)
,ao(test)
和vo(innertest)
,而innertest
的作用域鏈由當前執行環境的變數物件(未進入執行階段前)與上層環境的一系列活動物件組成,如下:
innertestec = ,
//作用域鏈
scopechain: [vo(innertest), ao(test), ao(global)],
//this指向
this: window
}
全域性環境下指向window
函式環境下需根據執行環境和執行方法確定(==後續補充==)
js進入執行階段後,**執行順序如下:
巨集任務(同步任務) --> 微任務 --> 巨集任務(非同步任務)
1.巨集任務:巨集任務又按執行順序分為同步任務和非同步任務
理解巨集任務中同步任務和非同步任務的執行順序,那麼就相當於理解了js非同步執行機制–事件迴圈(event loop
)
事件迴圈可以理解為由三部分組成:主線程執行棧、非同步任務等待觸發、**任務佇列
在js引擎主線程執行過程中:
首先執行巨集任務的同步任務,在主線程上形成乙個執行棧,可理解為函式呼叫棧;
當執行棧中的函式呼叫到一些非同步執行的api
(例如非同步ajax
,dom
事件,settimeout
等api
),則會開啟對應的執行緒(http
非同步請求執行緒,事件觸發執行緒和定時器觸發執行緒)進行監控和控制
當非同步任務的事件滿足觸發條件時,對應的執行緒則會把該事件的處理函式推進任務佇列(task queue
)中,等待主線程讀取執行
當js引擎主線程上的任務執行完畢,則會讀取任務佇列中的事件,將任務佇列中的事件任務推進主線程中,按任務佇列順序執行
當js引擎主線程上的任務執行完畢後,則會再次讀取任務佇列中的事件任務,如此迴圈,這就是事件迴圈(event loop
)的過程
2.微任務:是在es6
和node
環境**現的乙個任務型別.
微任務的示例:api
主要有:promise
,process.nexttick
console.log('script start');
settimeout(function() , 0);
promise.resolve().then(function() ).then(function() );
console.log('script end');
輸出結果:
script start
script end
promise1
promise2
settimeout
以上就是js執行的過程 你了解JS執行過程嗎?
正如我們了解的一樣,當我們書寫了js程式之後,開啟瀏覽器,我們的 就可以開始執行了 當然保證你的 沒有問題,才能按照你的預期進行執行 剛才說的是js執行的乙個大的環境,今天我們學習一下,js在解析器裡的乙個執行過程。這個過程分為兩個階段 變數物件的變化,和這兩個階段息息相關。在介紹這兩個階段之前,了...
js執行過程
執行過程 1.宿主環境 瀏覽器 把一段 給js引擎 js引擎按順序執行 因為是宿主環境發起,這也是一條巨集任務 2.需要知道每個巨集觀任務尾部會跟著微任務佇列 當有微觀任務出現,會把他放在微任務佇列中,在上一步的巨集任務執行完後再執行 3.若有巨集觀任務出現,會放入巨集觀任務佇列中,等待上一步微任務...
js 函式執行過程
函式執行過程中 1.每使用乙個變數,函式都會由近到遠的遍歷自己的好友列表中的作用域物件。2.如果在離自己近的格仔中找到了區域性變數,就優先使用區域性變數,不再去全域性找。3.如果在離自己近的格仔中沒找到要用的區域性變數,才被迫去全域性找,如果在全域性找到了想用的變數,則本次修改結果,會影響全部變數的...