事件迴圈深度學習
事件迴圈
學習事件迴圈 首先就要了解一下瀏覽器的程序模型
瀏覽器的程序模型
何為程序?
- 如果要執行一個程式 就要屬於他自己的
記憶體空間
可以把這塊記憶體空間簡單理解為程序 - 什麼
物件,函式啥啥啥的
都是放在記憶體裡面的 所以就需要開闢一塊記憶體空間讓這個程式自己去使用 - 總結 :
程序 == 開闢出的這塊記憶體空間
每一個應用 至少也要有一個程序
程序之間相互獨立
即使要通訊 也需要雙方同意才行 比如qq程序崩潰了 肯定是不會影響到微信的 所以每一個程序是完全獨立的
何為執行緒?
- 有了程序後 就可以執行程式的程式碼了
- 執行程式碼的
人
稱之為執行緒
一個
程序
至少有一個執行緒
所以在程序開啟後會自動建立一個執行緒
來執行程式碼 該執行緒稱之為主執行緒
如果程式需要同時執行多塊程式碼 主執行緒就會啟動更多的 執行緒來執行程式碼 所以
一個程序中可以包含多個執行緒
瀏覽器有哪些程序和執行緒
瀏覽器是一個多程序多執行緒的應用程式
- 瀏覽器內部工作極其複雜
- 為了避免相互影響 為了減少連環崩潰的機率
當瀏覽器啟動後 它會開啟多個程序
可以在瀏覽器的工作管理員中檢視當前的所有程序
其中最主要的程序有
- 瀏覽器程序 : 主要負責頁面的顯示 使用者互動 子程序管理等 瀏覽器程序內部會啟動多個執行緒處理不同的任務
- 網路程序 : 負責載入網路資源 網路程序內部會啟動多個執行緒來處理不同的網路任務
- 渲染程序(重點) : 渲染程序啟動後 會開啟一個
渲染主執行緒
, 主執行緒負責執行HTML,CSS,JS程式碼
預設情況下瀏覽器會為為每個標籤頁開啟一個新的渲染程序 以保證不同的標籤頁之間不相互影響
渲染主執行緒是如何工作的?
ps: 事件迴圈就在主執行緒中執行
- 渲染主執行緒是瀏覽器中最繁忙的執行緒 需要他處理的任務非常多
- 解析html,css,js,計算樣式,佈局,處理圖層,每秒把頁面畫60次.....
要處理這麼多的任務 主執行緒如何去排程指揮任務呢?
比如:
- 我正在執行一個js函式,執行到一半的時候使用者點選了按鈕, 我該立即去執行點選事件的處理函式嗎?
- 我正在執行一個js函式,執行到一半額時候某個計時器到達了時間,我改立即去實現它的回撥函式嗎?
- 瀏覽器程序通知我使用者點選了按鈕
,與此同時,某個計時器也到達了時間,我應該處理哪一個呢?
### 渲染主執行緒指揮排程核心的方法 排隊
以下的整個過程,被稱之為事件迴圈 也可以說訊息迴圈 - 在最開始的時候 渲染主執行緒會進入一個無限的迴圈 - 每一次迴圈會檢查事件佇列中是否有任務存在,
如果有,就取出第一個任務執行,執行完後進入下一次迴圈
,如果沒有就休息 - 其他所有執行緒 (包括其他進行的執行緒比如網路執行緒,監聽使用者互動的執行緒等等..
) ,可以隨時向事件佇列裡新增任務,新任務會加到事件佇列的末尾
,在新增新任務的時候,如果主執行緒是休眠狀態,則會喚醒以繼續迴圈拿去任務
事件迴圈的細節
非同步是什麼?
在程式碼執行過程中, 會遇到一些無法
立即處理
的任務 - 計時完成後需要執行的任務---setTimeOut,setInterval
- 網路通訊後需要執行的任務---XHR,Fetch
- 使用者操作後需要執行的任務---addEventListener
執行這些任務 都是需要
未知的時間的
,不能立即去執行如果讓渲染主執行緒等待這型別任務的時機達到,就會導致主執行緒長期處於
阻塞
的狀態 從而導致瀏覽器卡死!!!
```javascript setTimeOut(()=>{
console.log(1);
},300)
console.log(2); // 如果先等待3秒後列印1 然後再列印2 這就是同步 // 顯然 這樣是不可行的 因為一個定時器所有的任務都被阻塞了 // 那渲染主執行緒怎麼執行繪製頁面任務?怎麼執行事件互動任務? 直接廢了! ```
渲染主執行緒承擔著極其重要的工作,無論如何都不能阻塞!!!!
因此瀏覽器選擇用
非同步
來解決這個問題
- 比如主執行緒在事件佇列中遇到一個
定時器
- 主執行緒會派一個計時執行緒去開始執行定時
主執行緒是不會自己計時的, 他要幹別的活
,此時,在主執行緒眼裡,定時器這個的任務已經執行了 - 主執行緒然後繼續去執行後面的任務
- 突然
定時器時間到了!
, 定時器會把需要執行的回撥函式繼續放在事件佇列裡的末端
當成一個普通的任務去執行 此時,主執行緒也不會知道 這個任務就是當時定時器裡的回撥函式
依舊進行迴圈的執行任務
這樣使用非同步的方式: 渲染主執行緒永不阻塞!!!!
之前遇到過一個面試題 , 如何理解js的非同步?
學到這裡後 , 我現在會選擇這樣去回答 - js是一個
單執行緒
的語言 , 這是因為js只能執行在瀏覽器的渲染主執行緒
中,而渲染主執行緒只有一個 , 而渲染主執行緒承擔著非常的多的事情 ,渲染頁面 , 執行js啥啥的
都在裡面執行 - 如果使用同步
的方式 , 就極可能導致主執行緒阻塞
, 從而導致訊息佇列中的很多其他任務無法得到執行 , 這樣一來 , 繁忙的主執行緒白白浪費時間等待 , 導致頁面也會無法更新 , 給使用者造成卡死的狀態 - 所以瀏覽器選擇用非同步
方式來避免 , 具體做法就是當某些任務發生時 ,比如計時器 , 網路 , 事件監聽 ,
主執行緒將任務會交給其他執行緒去處理 , 自身立刻結束任務的執行 , 轉而執行後面的任務 , 當其他執行緒完成時 , 把那個回撥函式包裝
成任務 ,加入到事件佇列的末端排隊
, 等待主執行緒排程 - 這樣的一個模式 就是非同步 可以保證瀏覽器不阻塞
js為何阻塞渲染?
- 因為js和渲染都處於一個執行緒上面
- 假如點選按鈕修改文字 點選完按鈕後 文字已經修改了 但是還沒繪製在頁面上 要等
渲染任務
執行後才會繪製
任務有優先順序嗎?
任務沒有優先順序
但是訊息佇列 有優先順序
根據w3c的最新解釋
- 每個任務都有一個任務型別 , 同一個型別的任務必須在一個佇列
也就是一共有多個佇列
, 不同型別的任務可以分屬不同的佇列,在一個次事件迴圈中,瀏覽器可以根據實際情況從不同的佇列中區出任務執行 - 瀏覽器必須準備好一個微佇列 , 微佇列中的任務優先所有其他任務執行
他裡面的東西 所有都要給我等 連繪製任務 都要等 就是最高優先順序了
隨著瀏覽器的複雜度急劇提升 W3C不再使用巨集佇列的說法
在目前chrome的實現中 至少包含了下面的佇列
- 延時佇列 : 用於存放計時器到達後的回撥任務 , 優先順序中
- 互動列隊 : 用於存放使用者操作後產生的事件處理任務 , 優先順序高
- 微佇列 : 使用者存放需要最快執行的任務 優先順序最高
新增任務到微佇列的主要方式是使用
promise,....
列如 ```javascript // 立刻把一個函式新增到微佇列 最高執行 promise.resolve().then(函式)
setTimeOut(()=>{ // 第三步執行延時佇列中的任務 console.log(1); },0)
promise.resolve().then(()=>{ // 第二步執行微佇列中的任務 console.log(2); })
console.log(3); // 第一步先執行全域性js
// 3 2 1
```
面試題 : 闡述一下js的事件迴圈
- 事件迴圈又叫訊息迴圈
官方叫event loop 瀏覽器實現叫message loop
, 是瀏覽器選擇主執行緒的工作方式 , 在chrome中就是開啟了一個不會結束的for迴圈, 每次迴圈從訊息佇列中取出第一個任務執行,而其他執行緒只需要在合適的時候將任務加入到佇列末尾即可 - 過去吧訊息佇列簡單分為巨集佇列和微佇列,這種說法目前無法滿足複雜的瀏覽器環境,取而代之的是一種更加靈活多變的處理方式
- 根據w3c官方的解釋, 每個任務有不同的型別,同類型的任務必須在同一個佇列,不同的任務可以屬於不同的佇列.不同的任務佇列有不同的優先順序,在一次事件迴圈中,由瀏覽器自行決定取那個佇列的任務,但瀏覽器必須有一個微佇列,微佇列的任務一定具有最高的優先順序,必須有限排程執行--- title: 事件迴圈深度學習 tags: [js] date: 2022-09-31 16:09:29 categories: [js]
事件迴圈
學習事件迴圈 首先就要了解一下瀏覽器的程序模型
瀏覽器的程序模型
何為程序?
- 如果要執行一個程式 就要屬於他自己的
記憶體空間
可以把這塊記憶體空間簡單理解為程序 - 什麼
物件,函式啥啥啥的
都是放在記憶體裡面的 所以就需要開闢一塊記憶體空間讓這個程式自己去使用 - 總結 :
程序 == 開闢出的這塊記憶體空間
每一個應用 至少也要有一個程序
程序之間相互獨立
即使要通訊 也需要雙方同意才行 比如qq程序崩潰了 肯定是不會影響到微信的 所以每一個程序是完全獨立的
何為執行緒?
- 有了程序後 就可以執行程式的程式碼了
- 執行程式碼的
人
稱之為執行緒
一個
程序
至少有一個執行緒
所以在程序開啟後會自動建立一個執行緒
來執行程式碼 該執行緒稱之為主執行緒
如果程式需要同時執行多塊程式碼 主執行緒就會啟動更多的 執行緒來執行程式碼 所以
一個程序中可以包含多個執行緒
瀏覽器有哪些程序和執行緒
瀏覽器是一個多程序多執行緒的應用程式
- 瀏覽器內部工作極其複雜
- 為了避免相互影響 為了減少連環崩潰的機率
當瀏覽器啟動後 它會開啟多個程序
可以在瀏覽器的工作管理員中檢視當前的所有程序
其中最主要的程序有
- 瀏覽器程序 : 主要負責頁面的顯示 使用者互動 子程序管理等 瀏覽器程序內部會啟動多個執行緒處理不同的任務
- 網路程序 : 負責載入網路資源 網路程序內部會啟動多個執行緒來處理不同的網路任務
- 渲染程序(重點) : 渲染程序啟動後 會開啟一個
渲染主執行緒
, 主執行緒負責執行HTML,CSS,JS程式碼
預設情況下瀏覽器會為為每個標籤頁開啟一個新的渲染程序 以保證不同的標籤頁之間不相互影響
渲染主執行緒是如何工作的?
ps: 事件迴圈就在主執行緒中執行
- 渲染主執行緒是瀏覽器中最繁忙的執行緒 需要他處理的任務非常多
- 解析html,css,js,計算樣式,佈局,處理圖層,每秒把頁面畫60次.....
要處理這麼多的任務 主執行緒如何去排程指揮任務呢?
比如:
- 我正在執行一個js函式,執行到一半的時候使用者點選了按鈕, 我該立即去執行點選事件的處理函式嗎?
- 我正在執行一個js函式,執行到一半額時候某個計時器到達了時間,我改立即去實現它的回撥函式嗎?
- 瀏覽器程序通知我使用者點選了按鈕
,與此同時,某個計時器也到達了時間,我應該處理哪一個呢?
### 渲染主執行緒指揮排程核心的方法 排隊
以下的整個過程,被稱之為事件迴圈 也可以說訊息迴圈 - 在最開始的時候 渲染主執行緒會進入一個無限的迴圈 - 每一次迴圈會檢查事件佇列中是否有任務存在,
如果有,就取出第一個任務執行,執行完後進入下一次迴圈
,如果沒有就休息 - 其他所有執行緒 (包括其他進行的執行緒比如網路執行緒,監聽使用者互動的執行緒等等..
) ,可以隨時向事件佇列裡新增任務,新任務會加到事件佇列的末尾
,在新增新任務的時候,如果主執行緒是休眠狀態,則會喚醒以繼續迴圈拿去任務
事件迴圈的細節
非同步是什麼?
在程式碼執行過程中, 會遇到一些無法
立即處理
的任務 - 計時完成後需要執行的任務---setTimeOut,setInterval
- 網路通訊後需要執行的任務---XHR,Fetch
- 使用者操作後需要執行的任務---addEventListener
執行這些任務 都是需要
未知的時間的
,不能立即去執行如果讓渲染主執行緒等待這型別任務的時機達到,就會導致主執行緒長期處於
阻塞
的狀態 從而導致瀏覽器卡死!!!
```javascript setTimeOut(()=>{
console.log(1);
},300)
console.log(2); // 如果先等待3秒後列印1 然後再列印2 這就是同步 // 顯然 這樣是不可行的 因為一個定時器所有的任務都被阻塞了 // 那渲染主執行緒怎麼執行繪製頁面任務?怎麼執行事件互動任務? 直接廢了! ```
渲染主執行緒承擔著極其重要的工作,無論如何都不能阻塞!!!!
因此瀏覽器選擇用
非同步
來解決這個問題
- 比如主執行緒在事件佇列中遇到一個
定時器
- 主執行緒會派一個計時執行緒去開始執行定時
主執行緒是不會自己計時的, 他要幹別的活
,此時,在主執行緒眼裡,定時器這個的任務已經執行了 - 主執行緒然後繼續去執行後面的任務
- 突然
定時器時間到了!
, 定時器會把需要執行的回撥函式繼續放在事件佇列裡的末端
當成一個普通的任務去執行 此時,主執行緒也不會知道 這個任務就是當時定時器裡的回撥函式
依舊進行迴圈的執行任務
這樣使用非同步的方式: 渲染主執行緒永不阻塞!!!!
之前遇到過一個面試題 , 如何理解js的非同步?
學到這裡後 , 我現在會選擇這樣去回答 - js是一個
單執行緒
的語言 , 這是因為js只能執行在瀏覽器的渲染主執行緒
中,而渲染主執行緒只有一個 , 而渲染主執行緒承擔著非常的多的事情 ,渲染頁面 , 執行js啥啥的
都在裡面執行 - 如果使用同步
的方式 , 就極可能導致主執行緒阻塞
, 從而導致訊息佇列中的很多其他任務無法得到執行 , 這樣一來 , 繁忙的主執行緒白白浪費時間等待 , 導致頁面也會無法更新 , 給使用者造成卡死的狀態 - 所以瀏覽器選擇用非同步
方式來避免 , 具體做法就是當某些任務發生時 ,比如計時器 , 網路 , 事件監聽 ,
主執行緒將任務會交給其他執行緒去處理 , 自身立刻結束任務的執行 , 轉而執行後面的任務 , 當其他執行緒完成時 , 把那個回撥函式包裝
成任務 ,加入到事件佇列的末端排隊
, 等待主執行緒排程 - 這樣的一個模式 就是非同步 可以保證瀏覽器不阻塞
js為何阻塞渲染?
- 因為js和渲染都處於一個執行緒上面
- 假如點選按鈕修改文字 點選完按鈕後 文字已經修改了 但是還沒繪製在頁面上 要等
渲染任務
執行後才會繪製
任務有優先順序嗎?
任務沒有優先順序
但是訊息佇列 有優先順序
根據w3c的最新解釋
- 每個任務都有一個任務型別 , 同一個型別的任務必須在一個佇列
也就是一共有多個佇列
, 不同型別的任務可以分屬不同的佇列,在一個次事件迴圈中,瀏覽器可以根據實際情況從不同的佇列中區出任務執行 - 瀏覽器必須準備好一個微佇列 , 微佇列中的任務優先所有其他任務執行
他裡面的東西 所有都要給我等 連繪製任務 都要等 就是最高優先順序了
隨著瀏覽器的複雜度急劇提升 W3C不再使用巨集佇列的說法
在目前chrome的實現中 至少包含了下面的佇列
- 延時佇列 : 用於存放計時器到達後的回撥任務 , 優先順序中
- 互動列隊 : 用於存放使用者操作後產生的事件處理任務 , 優先順序高
- 微佇列 : 使用者存放需要最快執行的任務 優先順序最高
新增任務到微佇列的主要方式是使用
promise,....
列如 ```javascript // 立刻把一個函式新增到微佇列 最高執行 promise.resolve().then(函式)
setTimeOut(()=>{ // 第三步執行延時佇列中的任務 console.log(1); },0)
promise.resolve().then(()=>{ // 第二步執行微佇列中的任務 console.log(2); })
console.log(3); // 第一步先執行全域性js
// 3 2 1
```
面試題 : 闡述一下js的事件迴圈
- 事件迴圈又叫訊息迴圈
官方叫event loop 瀏覽器實現叫message loop
, 是瀏覽器選擇主執行緒的工作方式 , 在chrome中就是開啟了一個不會結束的for迴圈, 每次迴圈從訊息佇列中取出第一個任務執行,而其他執行緒只需要在合適的時候將任務加入到佇列末尾即可 - 過去吧訊息佇列簡單分為巨集佇列和微佇列,這種說法目前無法滿足複雜的瀏覽器環境,取而代之的是一種更加靈活多變的處理方式
- 根據w3c官方的解釋, 每個任務有不同的型別,同類型的任務必須在同一個佇列,不同的任務可以屬於不同的佇列.不同的任務佇列有不同的優先順序,在一次事件迴圈中,由瀏覽器自行決定取那個佇列的任務,但瀏覽器必須有一個微佇列,微佇列的任務一定具有最高的優先順序,必須有限排程執行