衆所周知JavaScript這門語言是單線程,可是爲何要設計成單線程呢?明明多線程更加有效率。前端
這裏咱們就要從JavaScript的用途來考慮,JavaScript是一門瀏覽器腳本語言,也就是說它須要操做DOM來更改頁面展現,提供用戶良好的上網體驗。這時候單線程的好處就體現出來,不妨想象一下:promise
若是JavaScript是多線程的語言,當一個線程正在進行一個DOM的刪除操做,這是另外一個線程出來搞事情,進行這個DOM的修改操做。這種狀況要怎麼處理呢?這樣的場景就會出現一些問題。瀏覽器
因此說JavaScript單線程的設計是從它的用途出發的,而且在之後也會一直堅持單線程的設計。bash
單線程就像是你們在食堂排隊打飯,若是想打到飯,那就必須等食堂大媽一個一個把排在前面的人的飯打完才能輪到你。可是,若是JavaScript真的是這樣那就糟糕了。不妨想一下,若是我訪問的這個網站有一個超清圖片,加載很慢,難道是要用戶等到圖片徹底加載出來以後才能進行其餘的操做嘛,顯然如今咱們瀏覽網站並不會出現這樣的狀況,那這又是怎麼一回事呢?多線程
那是由於JavaScript的任務分爲同步任務和異步任務兩種:異步
同步任務就是進入主線程的任務,必須排隊一個一個按順序的執行。函數
開發者們認識到,像費時的IO操做,接口請求徹底能夠不理他們,將他們暫時掛起,放入事件表(Event Table)中當,主線程中的任務執行完,再來「寵幸」它們。這種暫時掛起的任務就是異步任務。oop
每個異步任務都須要指定一個事件,例如當耗時的IO操做執行完以後,就會將它指定的這個事件添加到任務隊列中,這個事件就是回調函數。學習
因此說咱們常常說的主線程開始執行異步任務了,其實主線程執行的是異步任務的回調函數。網站
如今來分析一下上圖中的事件執行順序:
上述的過程會不斷的重複執行,這個重複的過程就是咱們一般所說的事件循環機制(Event Loop),看下面代碼:
console.log(1);
document.body.onclick = function () { console.log('2'); }
console.log(3);複製代碼
JavaScript中的給DOM註冊一個點擊事件,這個點擊事件其實就是一種異步任務,由於咱們不知道用戶何時纔會點擊。
如今咱們根據上圖來分析一下這段代碼的執行:
1.首先主線程會將同步的console.log操做放在主線程中執行,
2.首先打印出1,3
3.同時將點擊事件放入到事件表中,當用戶點擊body後,JS會在事件隊列中註冊點擊的回調函數。
4.這時主線程任務執行完畢,去任務隊列中檢查是否有須要執行的任務,這是發現了點擊body的回調函數,JavaScript就會將這個回調函數放在主線程中執行。
5.全部就打印出了1,3,2的結果。
異步任務其實還能夠細分爲宏任務和微任務,他們的區別就是執行順序的不一樣,下面咱們就討論一下他們具體的執行順序,在Event Loop中到底有什麼不一樣。
其實異步任務的執行是有兩個執行隊列的,一個是宏任務隊列,一個是微任務隊列,每次執行的時候,首先是去微任務隊列中查看是否有須要執行的任務,而後再去宏任務執行隊列中查看是否有須要執行的事件。
宏任務:總體的script代碼,setTimeout,setInterval、setImmediate
微任務:promise,process.nextTick
咱們如今根據這個流程圖來分析一下具體的執行順序:
如今咱們來分析一段代碼,看看輸出的順序是否符合上面的流程圖:
因此上述代碼最終的輸出應該是:1,6,7,2,4,9,10,5,11,8,3
但願你們看完這篇文章可以有收穫,哪裏寫的不對也但願各位大佬多加指點,本文章僅爲記錄前端小白的學習過程,謝謝你們!