<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                >[success]這里只介紹瀏覽器中的事件循環,node 中的事件循環放在 node.js 專題部分 [TOC] ## 靈魂三問 JavaScript 為什么是單線程的?JavaScript 為什么需要異步?JavaScript 單線程又是如何實現異步的? <span style="font-size: 20px;">1.JavaScript 為什么是單線程的?</span> 現在有 2 個線程 process1 process2,假設 JavaScript 是多線程的,所以他們可以對同一個 dom 同時進行操作。process1 刪除了該 dom,而 process2 編輯了該 dom,同時下達 2 個矛盾的命令,瀏覽器究竟該如何執行呢?這樣想,JavaScript 為什么被設計成單線程應該就容易理解了吧。 <span style="font-size: 20px;">2.JavaScript 為什么需要異步?</span> 如果 JavaScript 中不存在異步,只能自上而下執行,如果上一行解析時間很長,那么下面的代碼就會被阻塞。對于用戶而言,阻塞就意味著"卡死",這樣就導致了很差的用戶體驗,所以 JavaScript 中存在異步執行。 <span style="font-size: 20px;">3.JavaScript 單線程又是如何實現異步的呢?</span> 是通過**事件循環**來實現的 >為了利用多核 CPU 的計算能力,HTML5 提出 Web Worker 標準,允許 JavaScript 腳本創建多個線程,但是子線程完全受主線程控制,且不得操作 DOM。所以,這個新標準并沒有改變 JavaScript 單線程的本質。 為什么說 JavaScript 是“非阻塞”的語言?非阻塞即:“程序不會因為某個任務而停下來” ```js console.log("程序時間:" + new Date().getTime()) setTimeout(function () { console.log("暫停一秒:" + new Date().getTime()) }, 1000) console.log('這是暫停一秒之后的時間:' + new Date().getTime()) ``` 簡單來,如果上圖的 setTimeout 換成 C++ 的 sleep(1000) 之類的,那么 C++ 是會確實地“睡眠”那么段時間的,而 JS 不會。如果我就是想實現這個功能呢?可以利用 Promise 實現: ```js async function test () { console.log('start') await sleep(3000) console.log('3s has passed') } function sleep (ms) { return new Promise((resolve, reject) => { setTimeout(() => { resolve() }, ms) }) } ``` ## 任務隊列 當遇到一個異步事件后,JavaScript 引擎并不會一直等待異步事件返回結果,而是會將這個事件掛在與執行棧不同的隊列中,我們稱之為任務隊列。 這些任務又被細分為宏任務和微任務 - 宏任務(macrotask):script(全局任務),setTimeout ,setInterval ,setImmediate **(node.js 獨有)**,I/O(磁盤讀寫或網絡通信) ,UI rendering(UI交互事件) - 微任務(microtask):process.nextTick **(node.js 獨有)**, Promise.then, Object.observer(已廢棄), MutationObserver ## 事件循環(event loop) 這里首先要明確一點:瀏覽器是一個進程,其有多個線程(具體見 Broswer 章節) 一般情況下, 瀏覽器有如下五個線程: * GUI 渲染線程 * JavaScript 引擎線程 * 瀏覽器事件觸發線程 * 定時器觸發線程 * 異步 HTTP 請求線程 GUI 渲染線程和 JavaScript 引擎線程是互斥的,其他線程相互之間都是可以并行執行的。 瀏覽器中,JavaScript 引擎循環地從任務隊列中讀取任務并執行,這種運行機制就叫做事件循環。 ![](https://box.kancloud.cn/6ada796292f275f364445670068e36af_730x760.png) 更準確地說,事件循環是按下面幾個步驟執行的: 1. 執行同步代碼,這屬于宏任務(初始時的同步代碼就是 script 整體代碼) 2. 執行棧為空,查詢是否有微任務 (microtask) 需要執行 3. 執行所有微任務 4. 必要的話渲染 UI 5. 然后開始下一輪 Event loop,執行宏任務中的異步代碼 ## 例題 ```js setTimeout(function () { console.log(1) }, 0) Promise.resolve(function () { console.log(2) }) new Promise(function (resolve) { console.log(3) }) console.log(4) // 上述代碼的輸出結果是什么??? ``` 正確答案是`------------------->` 3 4 1 解釋如下: ``` js // 遇到 setTimeout 將 setTimeout 回調放入宏任務隊列中 setTimeout(function () { console.log(1) }, 0) // 遇到了 promise,但是并沒有 then 方法回調 // 所以這句代碼會在執行過程中進入我們當前的執行上下文 緊接著就出棧了 Promise.resolve(function () { console.log(2) }) // 遇到了一個 new Promise,Promise 有一個原則就是在初始化 Promise 的時候Promise 內部的構造器函數會立即執行, // 因此在這里會立即輸出一個 3,所以這個 3 是第一個輸出的 new Promise(function (resolve) { console.log(3) }) // 然后第二個輸出 4 當代碼執行完畢后回去微任務隊列查找有沒有任務, // 發現微任務隊列是空的,那么就去宏仁務隊列中查找,發現有一個我們剛剛放進去的setTimeout 回調函數, // 那么就取出這個任務進行執行,所以緊接著輸出1 console.log(4) ``` 太簡單了?來看看這題: ```js console.log('begin'); // 1.begin setTimeout(() => { console.log('setTimeout 1'); // 3.setTimeout 1 Promise.resolve() // Promise.resolve().then :直接把 then 回調放入微任務隊列 .then(() => { console.log('promise 1'); // 5.promise 1 setTimeout(() => { console.log('setTimeout2'); // 8. setTimeout2 }); }) .then(() => { console.log('promise 2'); // 7. promise 2 注意7比8要快,then 方法返回一個新的 Promise 對象 }); new Promise(resolve => { console.log('a'); // 4. a resolve(); }).then(() => { console.log('b'); // 6. b }); }, 0); console.log('end'); // 2.end ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看