1. 程式人生 > >JS瀏覽器賭博網站平臺出租事件迴圈機制

JS瀏覽器賭博網站平臺出租事件迴圈機制

程序、執行緒

  • 程序賭博網站平臺出租【大神原始碼論壇】dsluntan.com  【布丁原始碼論壇】budingbbs.com 企娥3393756370是系統分配的獨立資源,是 CPU 資源分配的基本單位,程序是由一個或者多個執行緒組成的。

  • 執行緒是程序的執行流,是CPU排程和分派的基本單位,同個程序之中的多個執行緒之間是共享該程序的資源的。

瀏覽器核心

  • 瀏覽器是多程序的,瀏覽器每一個 tab 標籤都代表一個獨立的程序(也不一定,因為多個空白 tab 標籤會合併成一個程序),瀏覽器核心(瀏覽器渲染程序)屬於瀏覽器多程序中的一種。

  • 瀏覽器核心有多種執行緒在工作。

    • GUI 渲染執行緒:

      • 負責渲染頁面,解析 HTML,CSS 構成 DOM 樹等,當頁面重繪或者由於某種操作引起迴流都會調起該執行緒。
      • 和 JS 引擎執行緒是互斥的,當 JS 引擎執行緒在工作的時候,GUI 渲染執行緒會被掛起,GUI 更新被放入在 JS 任務佇列中,等待 JS 引擎執行緒空閒的時候繼續執行。
    • JS 引擎執行緒:

      • 單執行緒工作,負責解析執行 JavaScript 指令碼。
      • 和 GUI 渲染執行緒互斥,JS 執行耗時過長就會導致頁面阻塞。
    • 事件觸發執行緒:

      • 當事件符合觸發條件被觸發時,該執行緒會把對應的事件回撥函式新增到任務佇列的隊尾,等待 JS 引擎處理。
    • 定時器觸發執行緒:

      • 瀏覽器定時計數器並不是由 JS 引擎計數的,阻塞會導致計時不準確。
      • 開啟定時器觸發執行緒來計時並觸發計時,計時完成後會被新增到任務佇列中,等待 JS 引擎處理。
    • http 請求執行緒:

      • http 請求的時候會開啟一條請求執行緒。
      • 請求完成有結果了之後,將請求的回撥函式新增到任務佇列中,等待 JS 引擎處理。
    image

JavaScript 引擎是單執行緒

JavaScript 賭博網站平臺出租【大神原始碼論壇】dsluntan.com  【布丁原始碼論壇】budingbbs.com 企娥3393756370引擎是單執行緒,也就是說每次只能執行一項任務,其他任務都得按照順序排隊等待被執行,只有當前的任務執行完成之後才會往下執行下一個任務。

HTML5 中提出了 Web-Worker API,主要是為了解決頁面阻塞問題,但是並沒有改變 JavaScript 是單執行緒的本質。瞭解 

Web-Worker

JavaScript 事件迴圈機制

JavaScript 事件迴圈機制分為瀏覽器和 Node 事件迴圈機制,兩者的實現技術不一樣,瀏覽器 Event Loop 是 HTML 中定義的規範,Node Event Loop 是由 libuv 庫實現。這裡主要講的是瀏覽器部分。

Javascript 有一個 main thread 主執行緒和 call-stack 呼叫棧(執行棧),所有的任務都會被放到呼叫棧等待主執行緒執行。

  • JS 呼叫棧

    JS 呼叫棧是一種後進先出的資料結構。當函式被呼叫時,會被新增到棧中的頂部,執行完成之後就從棧頂部移出該函式,直到棧內被清空。

  • 同步任務、非同步任務

    JavaScript 單執行緒中的任務分為同步任務和非同步任務。同步任務會在呼叫棧中按照順序排隊等待主執行緒執行,非同步任務則會在非同步有了結果後將註冊的回撥函式新增到任務佇列(訊息佇列)中等待主執行緒空閒的時候,也就是棧內被清空的時候,被讀取到棧中等待主執行緒執行。任務佇列是先進先出的資料結構。

  • Event Loop

    呼叫棧中的同步任務都執行完畢,棧內被清空了,就代表主執行緒空閒了,這個時候就會去任務佇列中按照順序讀取一個任務放入到棧中執行。每次棧內被清空,都會去讀取任務佇列有沒有任務,有就讀取執行,一直迴圈讀取-執行的操作,就形成了事件迴圈。

image

image

  • 定時器

    定時器會開啟一條定時器觸發執行緒來觸發計時,定時器會在等待了指定的時間後將事件放入到任務佇列中等待讀取到主執行緒執行。

    定時器賭博網站平臺出租【大神原始碼論壇】dsluntan.com  【布丁原始碼論壇】budingbbs.com 企娥3393756370指定的延時毫秒數其實並不準確,因為定時器只是在到了指定的時間時將事件放入到任務佇列中,必須要等到同步的任務和現有的任務佇列中的事件全部執行完成之後,才會去讀取定時器的事件到主執行緒執行,中間可能會存在耗時比較久的任務,那麼就不可能保證在指定的時間執行。

  • 巨集任務(macro-task)、微任務(micro-task)

    除了廣義的同步任務和非同步任務,JavaScript 單執行緒中的任務可以細分為巨集任務和微任務。

    macro-task包括:script(整體程式碼), setTimeout, setInterval, setImmediate, I/O, UI rendering。

    micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver。

        console.log(1);
        setTimeout(function() {
            console.log(2);
        })
        var promise = new Promise(function(resolve, reject) {
            console.log(3);
            resolve();
        })
        promise.then(function() {
            console.log(4);
        })
        console.log(5);
    

    示例中,setTimeout 和 Promise被稱為任務源,來自不同的任務源註冊的回撥函式會被放入到不同的任務佇列中。

    有了巨集任務和微任務的概念後,那 JS 的執行順序是怎樣的?是巨集任務先還是微任務先?

    第一次事件迴圈中,JavaScript 引擎會把整個 script 程式碼當成一個巨集任務執行,執行完成之後,再檢測本次迴圈中是否尋在微任務,存在的話就依次從微任務的任務佇列中讀取執行完所有的微任務,再讀取巨集任務的任務佇列中的任務執行,再執行所有的微任務,如此迴圈。JS 的執行順序就是每次事件迴圈中的巨集任務-微任務。

    • 上面的示例中,第一次事件迴圈,整段程式碼作為巨集任務進入主執行緒執行。
    • 遇到了 setTimeout ,就會等到過了指定的時間後將回調函式放入到巨集任務的任務佇列中。
    • 遇到 Promise,將 then 函式放入到微任務的任務佇列中。
    • 整個事件迴圈完成之後,會去檢測微任務的任務佇列中是否存在任務,存在就執行。
    • 第一次的迴圈結果列印為: 1,3,5,4。
    • 接著再到巨集任務的任務佇列中按順序取出一個巨集任務到棧中讓主執行緒執行,那麼在這次迴圈中的巨集任務就是 setTimeout 註冊的回撥函式,執行完這個回撥函式,發現在這次迴圈中並不存在微任務,就準備進行下一次事件迴圈。
    • 檢測到巨集任務佇列中已經沒有了要執行的任務,那麼就結束事件迴圈。
    • 最終的結果就是 1,3,5,4,2。