一 進程與線程
線程是進程執行的最小單位,進程是系統分配任務的最小單位。
一個進程可執行最少一個線程。線程分為子線程和主線程。
主線程關閉則子線程關閉。
二? 瀏覽器進程
瀏覽器是多進程多線程應用。
進程包括:
- 瀏覽器進程 負責程序交互
- 渲染進程 負責執行js等
- 網絡進程 負責網絡進程加載
渲染主線程負責執行js、vue,解釋css、html等。
一個標簽一個渲染進程。
渲染主線程執行最多次。
有線程將任務放到渲染主線程執行隊列,渲染主線程執行隊列從消息隊列中獲取任務執行。
同一類型任務在同一隊列中。
消息隊列包括:
- 微隊列 執行優先級最高
- 交互隊列 執行優先級中
- 延時隊列?執行優先級低 執行回調
三 js異步理解
js為單進程語言。渲染主線程中執行js。
使用同步則可能導致渲染主進程堵塞。
渲染主線程執行隊列其他任務無法執行。
瀏覽器采用異步方法可避免堵塞。
具體方法:
- 任務執行時,主線程將任務交給其他線程執行,主線程繼續執行后續代碼。
- 任務中回調函數,包裝為任務,加入到延時隊列中,待主進程執行。
以上方法最大限度保證單進程的流暢運行。
"主線程將任務交給其他線程執行"可以解釋為,執行代碼時,有線程將不同任務放到不同隊列,根據隊列執行優先級,主線程執行完全局任務后,獲取任務執行。
交互事件任務進入交互隊列。
Promise.resolve().then(function(){}) 將任務放入微隊列。
三 js事件循環
渲染主線程循環執行,各個隊列的任務,事件循環又叫消息循環。
類似于后端消息隊列,有守護線程監聽隊列,其他線程執行對應數據,監聽到有新數據就執行。
瀏覽器中開始死循環,執行消息隊列中的任務,其他線程將任務插入隊尾。
同類型的任務必須在同一隊列,不同的任務應屬于不同隊列。
不同隊列執行的優先級不同,微隊列必須再存且執行優先級最高,其他隊列優先級由瀏覽器自行決定。
四 js定時器是否精準
不精準
- 硬件沒有原子鐘
- 操作系統計時函數偏差,js計時執行操作系統函數
- 計時器實現時嵌套層級超過5層,則帶有4毫秒時間差
- 受渲染主線程事件循環影響,計時器的回調在延時隊列中,只能在渲染主線程空閑時運行,因此有偏差
原子鐘為一個硬件設備,目前有芯片級原子鐘。
國產芯片級微型原子鐘:多領域應用,市場前景廣闊!-電子發燒友網
五 示例
例:
const btn = document.getElementById("btn")function clickf(event){setTimeout(function(){console.log("setTimeout1")},0) Promise.resolve().then(function(){console.log("Promise1");})}btn.addEventListener('click', clickf(event));setTimeout(function(){btn.click(); },0) Promise.resolve().then(function(){console.log("Promise2");})function sleep(times){const date = Date.now();let currentDate = null;do {currentDate = Date.now();} while (currentDate - date < times);}function showaf(){let a=1console.log(a)}function showa(func){if (typeof func === 'function') {func(); // 執行回調函數}}function settimeout1(){console.log("setTimeout2")Promise.resolve().then(function(){console.log("Promise3");})console.log("setTimeout3") }setTimeout(settimeout1,0) showa(showaf)sleep(1000)let b=2console.log(b)
輸出結果
調用順序如下:
先是全局代碼執行,依次推入延時隊列任務1、微隊列任務1、延時隊列任務2。
根據推入順序和隊列的優先順序,依次執行微隊列任務1,延時隊列任務1,延時隊列任務2。
之后類推。
參考:
事件循環那點事_計算機硬件沒有原子鐘怎么理解-CSDN博客
?