<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 前言 `Event Loop`即事件循環,是瀏覽器或`Node`解決單線程運行時不會阻塞的一種機制。 在正式學習`Event Loop`之前,先需要解決幾個問題: 1. 什么是同步與異步? 2. `JavaScript`是一門單線程語言,那如何實現異步? 3. 同步任務和異步任務的執行順序如何? 4. 異步任務是否存在優先級? ## 同步與異步 計算機領域中的同步與異步和我們現實社會的同步和異步正好相反。現實中的同步,就是同時進行,突出的是"同",比如看足球比賽的時候吃著零食,兩件事情同時發生;異步就是不同時。但計算機中與現實存在一定差異。 ### 舉個栗子 天氣冷了,早上剛醒來想喝點熱水暖暖身子,但這每天起早貪黑996,晚上回來太累躺下就睡,沒開水啊,沒法子,只好急急忙忙去燒水。 現在早上太冷了啊,不由得在被窩里面多躺了一會,收拾的時間緊緊巴巴,不能空等水開,于是我便趁此去洗漱,收拾自己。 洗漱完,水開了,喝到暖暖的熱水,舒服啊! 舒服完,開啟新的996之日,打工人出發! 燒水和洗漱是在同時間進行的,這就是**計算機中的異步**。 **計算機中的同步**是連續性的動作,上一步未完成前,下一步會發生堵塞,直至上一步完成后,下一步才可以繼續執行。例如:只有等水開,才能喝到暖暖的熱水。 ## 單線程卻可以異步? `JavaScript`的確是一門單線程語言,但是瀏覽器`UI`是多線程的,異步任務借助瀏覽器的線程和`JavaScript`的執行機制實現。 例如,`setTimeout`就借助瀏覽器定時器觸發線程的計時功能來實現。 ### 瀏覽器線程 1. `GUI`渲染線程 * 繪制頁面,解析HTML、CSS,構建DOM樹等 * 頁面的重繪和重排 * 與JS引擎互斥(JS引擎阻塞頁面刷新) 2. `JS`引擎線程 * js腳本代碼執行 * 負責執行準備好的事件,例如定時器計時結束或異步請求成功且正確返回 * 與GUI渲染線程互斥 3. 事件觸發線程 * 當對應的事件滿足觸發條件,將事件添加到js的任務隊列末尾 * 多個事件加入任務隊列需要排隊等待 4. 定時器觸發線程 * 負責執行異步的定時器類事件:setTimeout、setInterval等 * 瀏覽器定時計時由該線程完成,計時完畢后將事件添加至任務隊列隊尾 5. `HTTP`請求線程 * 負責異步請求 * 當監聽到異步請求狀態變更時,如果存在回調函數,該線程會將回調函數加入到任務隊列隊尾 ## 同步與異步執行順序 1. `JavaScript`將任務分為同步任務和異步任務,同步任務進入主線中中,異步任務首先到`Event Table`進行回調函數注冊。 2. 當異步任務的**觸發條件滿足**,將回調函數從`Event Table`壓入`Event Queue`中。 3. 主線程里面的同步任務執行完畢,系統會去`Event Queue`中讀取異步的回調函數。 4. 只要主線程空了,就會去`Event Queue`讀取回調函數,這個過程被稱為`Event Loop`。 ### 舉個栗子 > * setTimeout(cb, 1000),當1000ms后,就將cb壓入Event Queue。 > * ajax(請求條件, cb),當http請求發送成功后,cb壓入Event Queue。 ### EventLoop執行流程 **Event Loop**執行的流程如下: ![1.webp](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b55d3524a0dc4352a731ccc6321e1e4d~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp?) 下面一起來看一個例子,熟悉一下上述流程。 ~~~ javascript復制代碼// 下面代碼的打印結果? // 同步任務 打印 first console.log("first"); setTimeout(() => { // 異步任務 壓入Event Table 4ms之后cb壓入Event Queue console.log("second"); },0) // 同步任務 打印last console.log("last"); // 讀取Event Queue 打印second ~~~ ### 常見異步任務 * `DOM`事件 * `AJAX`請求 * 定時器`setTimeout`和`setlnterval` * `ES6`的`Promise` ## 異步任務的優先級 下面繼續來看一個案例: ~~~ javascript復制代碼setTimeout(() => { console.log(1); }, 1000) new Promise(function(resolve){ console.log(2); for(var i = 0; i < 10000; i++){ i == 99 && resolve(); } }).then(function(){ console.log(3) }); console.log(4) ~~~ 按照上面的學習: 可以很輕松得出案例的打印結果:**2,4,1,3**。 > Promise定義部分為同步任務,回調部分為異步任務 將案例代碼在控制臺運行,最終返回結果卻有些出人意料: ![2.webp](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4dd50ce7e38c41ad94ba809aa656ec25~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp?) 剛看到如此結果,我的第一感覺是,`setTimeout`函數1s觸發太慢導致它加入`Event Queue`的時間晚于`Promise.then` 于是我修改了`setTimeout`的回調時間為0(瀏覽器最小觸發時間為`4ms`),但結果仍為發生改變。 那么也就意味著,`JavaScript`的異步任務是存在優先級的。 ## 宏任務和微任務 `JavaScript`除了廣義上將任務劃分為同步任務和異步任務,還對異步任務進行了更精細的劃分。異步任務又進一步分為微任務和宏任務。 ![3.webp](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/57ccee37e14042988106786ed382bd20~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp?) > * `history traversal`任務(`h5`當中的歷史操作) > * `process.nextTick`(`nodejs`中的一個異步操作) > * `MutationObserver`(`h5`里面增加的,用來監聽`DOM`節點變化的) 宏任務和微任務分別有各自的任務隊列`Event Queue`,即宏任務隊列和微任務隊列。 ## Event Loop執行過程 了解到宏任務與微任務過后,我們來學習宏任務與微任務的執行順序。 1. 代碼開始執行,創建一個全局調用棧,`script`作為宏任務執行 2. 執行過程過同步任務立即執行,異步任務根據異步任務類型分別注冊到微任務隊列和宏任務隊列 3. 同步任務執行完畢,查看微任務隊列 * 若存在微任務,將微任務隊列全部執行(包括執行微任務過程中產生的新微任務) * 若無微任務,查看宏任務隊列,執行第一個宏任務,宏任務執行完畢,查看微任務隊列,重復上述操作,直至宏任務隊列為空 更新一下`Event Loop`的執行順序圖: ![4.webp](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1a476f326234c7693debcc1d483fa41~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp?) ## 總結 在上面學習的基礎上,重新分析當前案例: ~~~ javascript復制代碼setTimeout(() => { console.log(1); }, 1000) new Promise(function(resolve){ console.log(2); for(var i = 0; i < 10000; i++){ i == 99 && resolve(); } }).then(function(){ console.log(3) }); console.log(4) ~~~ 分析過程見下圖: ![5.webp](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fedf8b829d8b48dbaf1e2366d7a345ad~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp?) ## 面試題 文章的最后附贈幾道經典面試題,可以測試一下自己對`Event Loop`的掌握程度。 ### 題目一 ~~~ js復制代碼console.log('script start'); setTimeout(() => { console.log('time1'); }, 1 * 2000); Promise.resolve() .then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); async function foo() { await bar() console.log('async1 end') } foo() async function errorFunc () { try { await Promise.reject('error!!!') } catch(e) { console.log(e) } console.log('async1'); return Promise.resolve('async1 success') } errorFunc().then(res => console.log(res)) function bar() { console.log('async2 end') } console.log('script end'); ~~~ ### 題目二 ~~~ js復制代碼setTimeout(() => { console.log(1) }, 0) const P = new Promise((resolve, reject) => { console.log(2) setTimeout(() => { resolve() console.log(3) }, 0) }) P.then(() => { console.log(4) }) console.log(5) ~~~ ### 題目三 ~~~ js復制代碼var p1 = new Promise(function(resolve, reject){ resolve("2") }) setTimeout(function(){ console.log("1") },10) p1.then(function(value){ console.log(value) }) setTimeout(function(){ console.log("3") },0) ~~~
                  <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>

                              哎呀哎呀视频在线观看