js的同步與異步

JavaScript語言的一大特色就是單線程,也就是說,同一個時間只能作一件事。那麼,爲何JavaScript不能有多個線程呢?這樣能提升效率啊。javascript


JavaScript的單線程,與它的用途有關。做爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題。好比,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另外一個線程刪除了這個節點,這時瀏覽器應該以哪一個線程爲準?css

因此,爲了不復雜性,從一誕生,JavaScript就是單線程,這已經成了這門語言的核心特徵,未來也不會改變。html

爲了利用多核CPU的計算能力,HTML5提出Web Worker標準,容許JavaScript腳本建立多個線程,可是子線程徹底受主線程控制,且不得操做DOM。因此,這個新標準並無改變JavaScript單線程的本質。前端

其實同步和異步,不管如何,作事情的時候都是隻有一條流水線(單線程),同步和異步的差異就在於這條流水線上各個流程的執行順序不一樣。vue

最基礎的異步是setTimeout和setInterval函數,很常見,可是不多人有人知道其實這就是異步,由於它們能夠控制js的執行順序。咱們也能夠簡單地理解爲:能夠改變程序正常執行順序的操做就能夠當作是異步操做。</pre>java

<script type="text/javascript">  
        console.log( "1" );  
        setTimeout(function() {  
            console.log( "2" )  
        }, 0 );  
        setTimeout(function() {  
            console.log( "3" )  
        }, 0 );  
          歡迎加入全棧開發交流划水交流圈:582735936
           面向划水1-3年前端人員
           幫助突破划水瓶頸,提高思惟能力

        setTimeout(function() {  
            console.log( "4" )  
        }, 0 );  

        console.log( "5" );  
</script>  </pre>
複製代碼

儘管咱們設置了setTimeout(function,time)中的等待時間爲0,結果其中的function仍是後執行。node

火狐瀏覽器的api文檔有這樣一句話:Because even though setTimeout was called with a delay of zero, it's placed on a queue and scheduled to run at the next opportunity, not immediately. Currently executing code must complete before functions on the queue are executed, the resulting execution order may not be as expected.webpack

意思就是:儘管setTimeout的time延遲時間爲0,其中的function也會被放入一個隊列中,等待下一個機會執行,當前的代碼(指不須要加入隊列中的程序)必須在該隊列的程序完成以前完成,所以結果可能不與預期結果相同。web

這裏說到了一個「隊列」(即任務隊列),該隊列放的是什麼呢,放的就是setTimeout中的function,這些function依次加入該隊列,即該隊列中全部function中的程序將會在該隊列之外的全部代碼執行完畢以後再以此執行,這是爲何呢?由於在執行程序的時候,瀏覽器會默認setTimeout以及ajax請求這一類的方法都是耗時程序(儘管可能不耗時),將其加入一個隊列中,該隊列是一個存儲耗時程序的隊列,在全部不耗時程序執行事後,再來依次執行該隊列中的程序。面試

又回到了最初的起點——javascript是單線程。單線程就意味着,全部任務須要排隊,前一個任務結束,纔會執行後一個任務。若是前一個任務耗時很長,後一個任務就不得不一直等着。因而就有一個概念——任務隊列。若是排隊是由於計算量大,CPU忙不過來,倒也算了,可是不少時候CPU是閒着的,由於IO設備(輸入輸出設備)很慢(好比Ajax操做從網絡讀取數據),不得不等着結果出來,再往下執行。因而JavaScript語言的設計者意識到,這時主線程徹底能夠無論IO設備,掛起處於等待中的任務,先運行排在後面的任務。等到IO設備返回告終果,再回過頭,把掛起的任務繼續執行下去。

因而,全部任務能夠分紅兩種,一種是同步任務(synchronous),另外一種是異步任務(asynchronous)。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有等主線程任務執行完畢,"任務隊列"開始通知主線程,請求執行任務,該任務纔會進入主線程執行。

具體來講,異步運行機制以下:

(1)全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)。

(2)主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。

(3)一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,因而結束等待狀態,進入執行棧,開始執行。

(4)主線程不斷重複上面的第三步。

只要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重複。

"任務隊列"是一個事件的隊列(也能夠理解成消息的隊列),IO設備完成一項任務,就在"任務隊列"中添加一個事件,表示相關的異步任務能夠進入"執行棧"了。主線程讀取"任務隊列",就是讀取裏面有哪些事件。

"任務隊列"中的事件,除了IO設備的事件之外,還包括一些用戶產生的事件(好比鼠標點擊、頁面滾動等等),好比$(selectot).click(function),這些都是相對耗時的操做。只要指定過這些事件的回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。

所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼,前面說的點擊事件$(selectot).click(function)中的function就是一個回調函數。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。例如ajax的success,complete,error也都指定了各自的回調函數,這些函數就會加入「任務隊列」中,等待執行。本次給你們推薦一個免費的學習羣,裏面歸納移動應用網站開發,css,html,webpack,vue node angular以及面試資源等。

相關文章
相關標籤/搜索