js 單線程和它的異步執行機制

單線程定義

單線程在程序執行時,所走的程序路徑按照連續順序排下來,前面的必須處理好,後面的纔會執行。
    單線程就是進程只有一個線程。
    多線程就是進程有多個線程。

Javascript 單線程

其實這裏Javascript的單線程運行機制和上面單線程定義是一個執行流程,它只有一個主線任務,好比:前面有一條河中間只有一根木棍,想要過河只能從一邊按順序走,單個單個的執行,若是從兩頭一塊兒過河Javascript的單線程就會形成阻塞,這裏只是舉例了一個簡單的解釋示例,雖然JavaScript是單線程的且效率過低只能循序漸進的一步步走,但是瀏覽器內部不是單線程的。你的一些I/O操做、定時器的計時和事件監聽(click, keydown...)等都是由瀏覽器提供的其餘線程來完成的

任務隊列和事件循環

  • 調用棧html

    代碼在運行過程當中,會有一個叫作調用棧的概念。調用棧是一種棧結構,它用來存儲計算機程序執行時候其活躍子程序的信息。(好比什麼函數正在執行,什麼函數正在被這個函數調用等等信息)

    代碼示例ajax

    function expale(a) {
           return a+1
       }
       console.log(expale(1))

    上面的例子咱們建立了一個簡單的函數,而後利用console打印並執行了這個函數,在console這裏執行的時候已經造成了一個棧,咱們也能夠比喻成一個比較大的盒子,console.log(expale(1))就是底部的一個盒子,而後expale(1)會變成另外一個盒子落在console.log(expale(1))上面這就造成了棧,其實就是上面所說到的存儲計算機程序執行時候其活躍子程序的信息。最後只想說由於它是單線程瀏覽器

  • 任務隊列多線程

    宏任務隊列:
                   setTimeout
                   setInterval
                   setImmediate
                   I/O 
                   UI rendering (瀏覽器渲染)
       微任務隊列:
                   process.nextTick(下一個事件輪詢的時間點上執行)
                   Promise
                   Object.observer
                   MutationObserver(監視 DOM 變更的接口)
             
       console.log('11221121');
       // 微任務
       Promise.resolve().then(() => {
           console.log('p 1');
       });
       
       // 宏任務
       setTimeout(() => {
           console.log('setTimeout');
       }, 0);

    等宏任務執行完(全局執行完)就會開始執行整個微任務隊列異步

  • 事件循環

clipboard.png

如上圖所示stack存儲着要執行的任務,下面黃色的onclick函數就是消息隊列,一旦有異步響應就會被推入到該隊列中。好比:用戶的點擊事件,setTimeout等等,而後再進入到stack棧中,而後再有任務進入消息隊列,再執行這樣就造成了事件循環
    
    單線程從任務隊列中讀取任務是不斷循環的,每次棧被清空後,都會在任務隊列中讀取新的任務,若是沒有新的任務,就會等待,直到有新的任務,這就叫任務循環。由於每一個任務都由一個事件所觸發,因此也叫事件循環。

異步機制

若是函數是異步的,發出調用以後,立刻返回,可是不會立刻返回預期結果。調用者沒必要主動等待,當被調用者獲得結果以後會經過回調函數主動通知調用者,上面我們也簡單的介紹了棧和任務隊列,以及簡單的事件循環,作了一些鋪墊

代碼函數

function send () {
       ajax()...
   }
   send()

上面是一段ajax的一段代碼執行,這時候單線程裏面已經有這個任務了,當咱們執行send()以後這個任務在頁面中其實已經完成了,可是咱們沒法拿到它的結果,在JavaScript中經過回調函數在耗時操做執行完成後把相應的結果信息傳遞給回調函數,通知執行JavaScript代碼的線程執行回調,這也就應上面那句話「不會立刻返回預期結果」oop

瀏覽器常駐線程

  • 渲染引擎線程:顧名思義,該線程負責頁面的渲染
  • JS引擎線程:負責JS的解析和執行
  • 定時觸發器線程:處理定時事件,好比setTimeout, setInterval
  • 事件觸發線程:處理DOM事件
  • 異步http請求線程:處理http請求

在這裏咱們要注意js引擎和渲染線程是不能同時進行的,渲染要在js引擎以前spa

代碼

setTimeout(function(){
        console.log('timer a');
    }, 0)
    
    for(var j = 0; j < 5; j++){
        console.log(j);
    }
    
    setTimeout(function(){
        console.log('timer b');
    }, 0) 
    console.log('click begin');

setTimeout的做用是操做者能夠設定時間插隊,咱們能夠把它想象成一個會員,有特殊待遇,你能夠插隊,可是這裏的setTimeout(fn, 0)是將函數插入執行隊列,等待執行,可是它不會當即執行,不是當即執行,下面的代碼就是一個很好的例子 b a線程

setTimeout(function() {
        console.log("a")
    }, 0)
    
    console.log("b")
總結
其實JavaScript單線程並不孤單(瀏覽器的其餘線程幫助它),它只是執行棧內的同步任務,執行完以後會再次執行下一個,直到執行完爲止,而後棧中無任務事件,它就會等待直到它出現,一直這樣的循環下去

參考文章
JavaScript異步機制詳解code

JavaScript單線程和異步機制

阮老師Event Loop

相關文章
相關標籤/搜索