自己寫的代碼,執行結果總是在你意料之中嗎?

之所以這樣問,是因為在日常工作中,有的同事總是對自己寫的代碼執行結果很驚訝,有時候只能用'見鬼'和'懷疑人生來'來描述。

驚訝源於不理解

今天和大家分享一下JavaScript的核心

單線程與異步

JavaScript是單線程腳本語言

首先我們要明確一點,JavaScript不管怎麼執行都是單線程工作,也就是說同一個時間只能做一件事。JavaScript的單線程,與它的用途有關,作為瀏覽器腳本語言,JavaScript的主要用途是與用戶交互,以及操作DOM。這決定了它只能是單線程,否則會帶來很多複雜的同步問題。為了利用多核CPU的計算能力,雖然HTML5提出了Web Worker,允許JavaScript腳本創建多個線程,但是子線程完全受主線程控制,且不得操作DOM和BOM。所以,依然沒有改變JavaScript是單線程的本質。

既然說Javascript是單線程工作,那怎麼還會有異步?這不是自相矛盾嗎?

其實,單線程和異步確實不能同時成為一個語言的特性。js選擇了成為單線程的語言,所以它本身不可能是異步的,但js的宿主環境(比如瀏覽器,Node)是多線程的,宿主環境通過某種方式(事件驅動,下文會講)使得js具備了異步的屬性

所以說,一種語言的牛逼往往不是看語言本身,而是看他運行的環境

EventLoop

先看一段金典的代碼:

自己寫的代碼,執行結果總是在你意料之中嗎?

我們發現,按照正常的邏輯思維,代碼應該依次打印1,2,3。但是現在2卻最後打印出來了,說明代碼在執行的時候並不是重上到下依次執行(雖然定時器的時間設置為0)

這就要引入一個概念

宏任務

javascript是單線程,在自己的主線程裡面跑著的一直是一個一個宏任務,瀏覽器在執行到定時器函數時,會為定時器函數專門開一個宏任務,也就是下一個宏任務才能執行到定時器函數

執行流程圖如下:

自己寫的代碼,執行結果總是在你意料之中嗎?

這就不難理解為什麼定時器裡面的東西最後打印出來了,同時也說明了定時器在定時的時候有誤差的原因(因為他要等著前面的宏任務執行完畢再執行)。

看似很完美,其實才剛剛開始

我們看下面的代碼:

自己寫的代碼,執行結果總是在你意料之中嗎?

打印出來的結果和你預期的相同嗎?

微任務

有宏任務就的有微任務,就像當大哥就的有小弟一樣

當瀏覽器執行完一個宏任務後,就會看看有沒有微任務執行,如果有微任務執行,就會先把當前的微任務執行完,再去執行下一個宏任務

微任務的代表有ajax,回調函數,和Promise

如下執行:

自己寫的代碼,執行結果總是在你意料之中嗎?

主線程從“任務隊列”中讀取事件,這個過程是循環不斷的,所以整個過程的這種運行機制又稱為Event Loop(事件循環)

總結

整個EventLoop的執行原理好比醫生和病人看病

假設只有一個醫生,大家都排隊(主隊)看病,醫生一次只能看一個(單線程),但是有的病人需要做檢查,那醫生就給他開單子,讓他拿著單子去做檢查(異步),這個時候醫生也不能等著什麼也不幹(浪費資源),然後接著看下面的病人,這時,做檢查的那個人回來了,就排到了另一隊(輔隊)。醫生在主隊每次看完一個病人都要去看看輔隊有沒有人做完檢查(時間輪詢),如果有就會先把輔隊的病人看完,然後再去主隊裡看下一個病人。

來波硬廣:感覺有收穫就關注哦!


分享到:


相關文章: