試着講清楚:js代碼運行機制


js運行機制

經常看文章的說到js是單線程的,其實這個說法非常的模糊和誤導性,准確的是js執行引擎是單線程的(js運行環境不止js引擎),js執行引擎就是js代碼的執行器,有了這些概念就可以下來說說js是如何運行的了。

3種特殊的js代碼類型

在js代碼執行的時候,js的代碼是按照順序執行的,從上到下,這個時候是同步執行的,不過,有幾個例外,先記下來:

  • 異步的網絡請求
  • 事件綁定、事件監聽器
  • 時間觸發函數

3種代碼特殊在哪?

我們模擬一下,js引擎遇到這三類代碼的情況:

  1. js代碼被執行好好的,正在順序執行代碼,這個時候呢,遇到了異步的網絡請求的代碼,調用了之后沒有等待網絡結果,就繼續執行之后的js代碼了,這與js代碼執行是單線程的不符合(不考慮h5),那么肯定異步網絡請求調用之后,不是js執行引擎管理了。
    問題一:誰在等待,誰之后通知js執行引擎結果,畢竟是js代碼就得js引擎是執行。

  2. 有了第一個問題,我們已經知道肯定有除了js執行引擎之外的模塊參與了上面的事情了,先放着不討論,之后js代碼繼續執行着,然后遇到了事件綁定和事件監聽函數,哦,這個js調用之后,也是繼續往下走的,並沒有調用那些函數內容,這與js代碼執行是單線程的不符合(不考慮h5),我們知道,事件函數只有在事件觸發的時候會起作用。那么問題來了:
    問題二:誰把事件關聯的函數保存的,以便接收事件觸發選擇正確的事件處理函數,通知js執行引擎?

  3. js代碼在遇到setTimeout和setInternal函數的時候,也是不直接執行,畢竟里面的代碼也沒有立刻執行,那么問題產生了如下問題:
    問題三:誰在監視時間流逝選擇合適的觸發函數通知js引擎執行的?

以上3點是在自己學習js的運行機制和js執行引擎的時候,遇到了3個問題,那么3個問題其中的js執行js代碼,但是監視肯定不是js執行引擎,答案如下:

  1. 異步網絡請求線程
  2. 事件觸發線程
  3. 定時觸發器線程

以上3個線程是獨立於js執行引擎之外,幫助處理這3類代碼的,所以啊,千萬不要認為js引擎什么都做,加上gui渲染線程,js執行引擎線程,5個線程齊了。

3種代碼如何執行?

以上我們了解了js執行的代碼和3個額外的線程協助下,js執行代碼構建了完備的環境了,但是js執行引擎是如何執行這3類線程給的函數的?畢竟js代碼都是在js執行引擎里面執行的:
答案是隊列(暫且叫做Message Queue)

3個線程根據功能職責,會把要執行的代碼封裝成一個結構(消息),放到隊列里面,js執行完同步代碼之后,才會循環的在這個隊列里面取結構(消息),取到了,那么就執行,取不到了就等待。

從以上的一個執行邏輯,那么我們就可以得出一個結論:
js在遇到這3類代碼的時候,一定滯后於同步代碼的
因為同步代碼執行完成之后,js執行引擎才會從隊列中取一條結構(消息)去執行,並且執行完成之后才會再取下一條。

以上也就是為什么我們經常看到時間處理函數總是在同步代碼之后執行的原因、異步網絡請求的回調函數也在同步代碼執行完成之后調用的原理;就是因為這3類函數被3類線程放到了隊列里了,而隊列里面的代碼在js執行完同步代碼之后才能執行。

setTimeout為什么不能恰到好處的執行呢,這是因為定時觸發器線程只是在時間到了之后,把應該執行的函數進行封裝放到隊列里面而已,具體什么時候執行還得看之前隊列含有多少消息沒有被處理。

gui渲染線程與js執行引擎的交互機制

上面說了3個執行線程與js執行引擎的交互,這個基本上沒有問題了,這下說說渲染與js代碼之間的交互。

在剛開始寫js代碼時代,肯定遇到過js代碼執行性能問題,比如頁面直接就不動彈了半天,這個時候其實可以得出來一個結論:js執行的時候,渲染是阻塞的,之后查了資料,發現這個定義更准確的說法是:js執行引擎的線程和gui渲染線程是互斥的

這也能解釋為什么js執行時間長后渲染不動的問題了;那么一個新的問題來了,如果是這樣的話,那么渲染引擎肯定就不能渲染,至少在js隊列不空的情況下,根本沒有機會渲染的,那么就可以做一個代碼不斷的使用setInternal不斷的往隊列里面填消息。事實真的是這樣嗎?

肯定不是這樣的,實際的瀏覽器沒有是這樣的,那么到底是哪塊讓js引擎和gui執行引擎的線程進行切換的,同步代碼肯定不行,那么就是隊列這塊了,肯定不是隊列為空的情況切換的,因為實際的js代碼在改了之后基本上就渲染了,那么基本上確定,是在每一次消息之間執行的,因為js代碼在執行的時候是同步的,做了這個假設之后,再查了大量的資料,有一篇文章是這樣描述的,在每次執行完一個消息之后,馬上切換到渲染線程執行渲染效果,然后渲染完成再切換js代碼執行取下一個消息。

至此渲染和js代碼執行的交互就了解了。(渲染線程是每次都需要切換的嗎?這個已經屬於性能優化內容了,就暫時不了解了)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM