標籤:代碼 work send 順序 一個 介面 迴圈 ready end
瀏覽器中的js程式是單線程的,那非同步呼叫是怎麼實現的呢?計時器是靠誰實現的呢?單線程難道是一邊執行程式一邊計時嗎?
好了 …………之前就有好多的疑問 ,現在按我的理解和大家說一說
一、JavaScript單線程
在瀏覽器中,執行JS程式只有一個線程,所以是單線程,所以執行順序就是從上到下依次執行,同一段時間內只能有一段代碼被執行。你可能會問,為什麼不用多線程呢,這樣不是更能充分利用CPU嗎?
ps:只能說早期的頁面非常簡單,所以我認為設計者沒有考慮多線程的問題 (本人猜想的哈,勿噴!!)。另外,JavaScript主要用來處理使用者與介面的互動,以及操作DOM;可以設想一下,如果一個線程要求刪除DOM,另一個線程要求修改呢,瀏覽器聽誰的??這就增加了程式設計的複雜度,所以簡單點好啊,你說是不是。
ps:雖然JavaScript是單線程的,可是瀏覽器內部不是單線程的啊,你的一些I/O操作、定時器和事件監聽是由瀏覽器提供的其他線程完成的……
##如果想利用多執行緒一些耗時較長的任務,可以使用HTML5提供的Web Worker、
二、任務隊列和事件迴圈
理解非同步機制的兩個要點:任務隊列和事件迴圈
ps:
三、非同步機制
有了上面兩節做鋪墊,理解非同步機制就容易多了。拿ajax來說,當頁面的單線程執行xhr.send()
之後,對於頁面來說發送任務已經完成了。怎麼發送,那是瀏覽器的事,和單線程無關;什麼時候響應,這事說不準。為了及時地得到響應的內容,在單線程中註冊相應的事件就好xhr.onreadystatechange = fn() {...}
。註冊之後,瀏覽器會在內部的其他線程中自動地幫我們監聽該事件。直到該事件被觸發,瀏覽器會在任務隊列中添加一個任務等待該單線程執行。
四、定時器
setTimeout的作用是在間隔一定的時間後,將回呼函數插入任務隊列中,等棧中的同步任務都執行完畢後,再執行。因為棧中的同步任務也會耗時,所以間隔的時間一般會大於等於指定的時間。
setTimeout(fn, 0)
的意思是,將回呼函數fn立刻插入任務隊列,等待執行,而不是立即執行。看一個例子:
五、總結所謂的單線程並不孤單,它的背後有瀏覽器的其他線程為其服務,其非同步也得靠其他線程來監聽事件的響應,並將回呼函數推入到任務隊列等待執行。單線程所做的就是執行棧中的同步任務,執行完畢後,再從任務隊列中取出一個事件(沒有事件的話,就等待事件),然後開始執行棧中相關的同步任務,不斷的這樣迴圈。
JavaScript 是單線程的而且是非同步機制