天天看點

js線程機制

前幾日寫了一篇文章,介紹了js阻塞頁面加載的問題。當時是通過例子來驗證的。今天,我介紹一下浏覽器核心,從原理上介紹一下js阻塞頁面加載的原因。

js線程機制

浏覽器的核心是多線程的,它們在核心制控下互相配合以保持同步,一個浏覽器至少實作三個常駐線程:javascript引擎線程,GUI渲染線程,浏覽器事件觸發線程。

1.        javascript引擎是基于事件驅動單線程執行的,JS引擎一直等待着任務隊列中任務的到來,然後加以處理,浏覽器無論什麼時候都隻有一個JS線程在運作JS程式。

2.        GUI渲染線程負責渲染浏覽器界面,當界面需要重繪(Repaint)或由于某種操作引發回流(reflow)時,該線程就會執行。但需要注意 GUI渲染線程與JS引擎是互斥的,當JS引擎執行時GUI線程會被挂起,GUI更新會被儲存在一個隊列中等到JS引擎空閑時立即被執行。

3.        事件觸發線程,當一個事件被觸發時該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理。這些事件可來自JavaScript引擎目前執行的代碼塊如setTimeOut、也可來自浏覽器核心的其他線程如滑鼠點選、AJAX異步請求等,但由于JS的單線程關系所有這些事件都得排隊等待JS引擎處理。

由上文藍色标注的文字可以知道,當浏覽器在執行JS程式的時候,GUI渲染線程會被儲存在一個隊列中,直到JS程式執行完成。這樣就造成了頁面的渲染,就是所說的JS阻塞頁面加載問題。

很多同學朋友搞不清楚,既然說JavaScript是單線程運作的,那麼XMLHttpRequest在連接配接後是否真的異步?

其實請求确實是異步的,不過這請求是由浏覽器新開一個線程請求(參見上圖),當請求的狀态變更時,如果先前已設定回調,這異步線程就産生狀态變更事件放到 JavaScript引擎的處理隊列中等待處理,當任務被處理時,JavaScript引擎始終是單線程運作回調函數,具體點即還是單線程運作 onreadystatechange所設定的函數.

參考資料:

http://fed.renren.com/2010/01/247

http://www.phpv.net/html/1700.html

來源:http://hi.baidu.com/zhoumm1008/blog/item/51105a49000bd5eed62afc6d.html

繼續閱讀