單執行緒
JavaScript語言具有單執行緒的特點,同一個時間只能做一件事情。這是因為JavaScript指令碼語言是為了處理頁面中使用者的互動,以及操作DOM而誕生的。如果對某個DOM元素進行新增和刪除,不同同時進行。應該是先新增,再刪除,事件有序。
單執行緒的特點是所有任務都需要排隊進行,前一個任務結束,才會執行後一個任務。這樣會導致問題:如果JS執行時間過長,這樣會導致頁面渲染不連貫,導致頁面渲染載入阻塞。
同步與非同步
為了解決這個問題,利用多核 CPU 的計算能力,HTML5 提出 Web Worker 標準,允許 JavaScript指令碼建立多個執行緒,JS中出現了同步和非同步。
同步
前一個任務結束後再執行後一個任務
如:
console.log(1);
console.log(2);
console.log(3);
// 1 2 3
非同步
在做這件事的同時,你還可以去處理其他事情
如:
console.log(1);
setTimeout(function() {
console.log(3);
},1000);
console.log(2);
// 1 2 3
如果按同步執行,要先透過定時器執行完才執行下一步,瀏覽器效率大大降低。
所以非同步可以先列印 2 等定時器時間到再列印3
事件迴圈
如果這樣,結果列印的是什麼呢?
console.log(1);
setTimeout(function() {
console.log(3);
},0);
console.log(2);
- JavaScript的同步任務在主執行緒中執行,形成一個執行棧
- 非同步任務透過回撥函式實現,把任務新增到任務佇列中
執行步驟:
- 先執行執行棧中的同步任務
- 非同步任務(回撥函式)放入任務佇列中
- 一旦執行棧中的所有同步任務執行完畢,系統就會按次序讀取任務佇列中的非同步任務,於是被讀取的非同步任務結束等待狀態,進入執行棧,開始執行
所以上面列印的結果還是1 2 3
類似的
console.log(1);
document.onclick = function() {
console.log('click');
}
console.log(2);
setTimeout(function() {
console.log(3)
}, 3000)
// 列印1 2 如果點選了,列印click,無論是否點選3秒後都列印3
同步任務放在執行棧中執行,非同步任務由非同步程式處理放到任務佇列中,執行棧中的任務執行完畢會去任務佇列中檢視是否有非同步任務執行,由於主執行緒不斷的重複獲得任務、執行任務、再獲取任務、再執行,所以這種機制被稱為事件迴圈( event loop)
。
執行步驟