說到js的單線程(single threaded)和異步(asynchronous),不少同窗不由會想,這不是自相矛盾麼?其實,單線程和異步確實不能同時成爲一個語言的特性。js選擇了成爲單線程的語言,因此它自己不多是異步的,但js的宿主環境(好比瀏覽器,Node)是多線程的,宿主環境經過某種方式(事件驅動,下文會講)使得js具有了異步的屬性。往下看,你會發現js的機制是多麼的簡單高效!javascript
js是單線程語言,瀏覽器只分配給js一個主線程,用來執行任務(函數),但一次只能執行一個任務,這些任務造成一個任務隊列排隊等候執行,但前端的某些任務是很是耗時的,好比網絡請求,定時器和事件監聽,若是讓他們和別的任務同樣,都老老實實的排隊等待執行的話,執行效率會很是的低,甚至致使頁面的假死。因此,瀏覽器爲這些耗時任務開闢了另外的線程,主要包括http請求線程,瀏覽器定時觸發器,瀏覽器事件觸發線程,這些任務是異步的。下圖說明了瀏覽器的主要線程。
圖片來自popAnt 畫得太好,忍不住引過來 (http://blog.csdn.net/kfanning/article/details/5768776)html
剛纔說到瀏覽器爲網絡請求這樣的異步任務單獨開了一個線程,那麼問題來了,這些異步任務完成後,主線程怎麼知道呢?答案就是回調函數,整個程序是事件驅動的,每一個事件都會綁定相應的回調函數,舉個栗子,有段代碼設置了一個定時器前端
setTimeout(function(){ console.log(time is out); },50);
執行這段代碼的時候,瀏覽器異步執行計時操做,當50ms到了後,會觸發定時事件,這個時候,就會把回調函數放到任務隊列裏。整個程序就是經過這樣的一個個事件驅動起來的。
因此說,js是一直是單線程的,瀏覽器纔是實現異步的那個傢伙。java
js一直在作一個工做,就是從任務隊列裏提取任務,放到主線程裏執行。下面咱們來進行更深一步的理解。
圖片來自Philip Roberts的演講《Help, I'm stuck in an event-loop》很是深入!
咱們把剛纔瞭解的概念和圖中作一個對應,上文中說到的瀏覽器爲異步任務單獨開闢的線程能夠統一理解爲WebAPIs,上文中說到的任務隊列就是callback queue,咱們所說的主線程就是有虛線組成的那一部分,堆(heap)和棧(stack)共同組成了js主線程,函數的執行就是經過進棧和出棧實現的,好比圖中有一個foo()函數,主線程把它推入棧中,在執行函數體時,發現還須要執行上面的那幾個函數,因此又把這幾個函數推入棧中,等到函數執行完,就讓函數出棧。等到stack清空時,說明一個任務已經執行完了,這時就會從callback queue中尋找下一我的任務推入棧中(這個尋找的過程,叫作event loop,由於它老是循環的查找任務隊列裏是否還有任務)。ajax
setTimeout(function(){ console.log(1); },0); console.log(2);
這段代碼的輸出結果是2,1。由於執行setTimeou後,會當即把匿名函數放到callback queue裏面等待主線程的召喚,但這個時候stack裏面並非空的,由於還有一句console.log(2)。等到執行完console.log(2)後,才經過event loop把匿名函數放到stack裏面。因此setTimeout(f1,0)這個語句並非沒有意義,若是f1是很耗時的任務,那就應該把任務放到callback queue裏面,等到主程序執行完後再執行。vim
咱們已經知道,js一直是單線程執行的,瀏覽器爲幾個明顯的耗時任務單獨開闢線程解決耗時問題,可是js除了這幾個明顯的耗時問題外,可能咱們本身寫的程序裏面也會有耗時的函數,這種狀況怎麼處理呢?咱們確定不能本身開闢單獨的線程,但咱們能夠利用瀏覽器給咱們開放的這幾個窗口,瀏覽器定時器線程和事件觸發線程是好利用的,網絡請求線程不適合咱們使用。下面咱們具體看一下:瀏覽器
假設耗時函數是f1,f1是f2的前置任務。網絡
function f1(callback){ setTimeout(function(){ // f1 的代碼 callback(); },0); } f1(f2);
這種寫法的耦合度高。多線程
$f1.on('custom',f2); //這裏綁定事件以jQuery寫法爲例 function f1(){ setTimeout(function(){ // f1的代碼 $f1.trigger('custom'); },0); }
這種方法經過綁定自定義事件,對方法一解耦,這樣能夠經過綁定不一樣的事件,實現不一樣的回調函數,但若是應用這種方法過多,不利於閱讀程序。app
參考內容:
http://www.sohamkamani.com/blog/2016/03/14/wrapping-your-head-around-async-programming/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
https://vimeo.com/96425312
http://blog.csdn.net/kfanning/article/details/5768776
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html