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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                >[success] # js -- 宏任務和微任務 1. 事件循環中并非只維護著一個隊列,事實上是有兩個隊列 1.1. **宏任務隊列**(macrotask queue):ajax、setTimeout、setInterval、DOM監聽、UI Rendering等 1.2. **微任務隊列**(microtask queue):Promise的then回調、 Mutation Observer API、queueMicrotask()等 2. 執行任何一個宏任務之前(不是隊列,是一個宏任務),都會先查看微任務隊列中是否有任務需要執行也就是宏任務執行之前,必須保證微任務隊列是空的;如果不為空,那么就優先執行微任務隊列中的任務(回調); >[danger] ##### 宏任務和微任務API * **異步宏任務:macrotask** 定時器:setTimeout/setInterval 事件綁定/隊列 數據請求:Ajax/Fetch MessageChannel setImmediate「NODE」 * **異步微任務:microtask** Promise.then/catch/finally async/awai queueMicrotask MutationObserver IntersectionObserver requestAnimationFrame process.nextTick「NODE」 ... >[danger] ##### 微任務隊列 1. 以微任務Promise 為例,其實進入隊列部分是**then 回調**,整個executor(執行器) 里的代碼是同步的,但是then 中的回調進入微任務隊列中等待值返回后進入js引擎中執行 ~~~ new Promise((resolve, reject) => { console.log("2222222") console.log("-------1") console.log("-------2") resolve() console.log("-------3") }).then(res => { console.log("then傳入的回調: res", res) }) ~~~ ![](https://img.kancloud.cn/64/45/64454e88dca057903869a3c2d05d11b7_237x108.png) >[success] # Promise 和 setTimeout 到底誰先執行 [Chrome開發工程師一篇文章](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) >[info] ## 定時器的介紹 ~~~ 1.需要重點注意的是`setTimeout(…)`不會自動的把你的回調放到事件循環隊列中。它設置了一個定時器。 當定時器過期了,宿主環境會將你的回調放到事件循環隊列中,以便在以后的循環中取走執行它。 看看下面的代碼: setTimeout(myCallback, 1000); 2.這并不意味著`myCallback`將會在 1,000ms 之后執行,而是,在 1,000ms 之后將被添加到事件隊列。 然而,這個隊列中可能會擁有一些早一點添加進來的事件 —— 你的回調將會等待被執行 ~~~ >[danger] ##### JavaScript高級程序設計(第3版)中的一個案例來說明定時器會延遲執行 ~~~ 1.下面代碼有一個點擊事件,當點擊事件結束觸發,會觸發里面的定時器,那么定時器真的會在事件觸發的250ms 后執行么? 答案:盡管在 255ms 處添加了定時器代碼,但這時候還不能執行,因為 onclick 事件處 理程序仍在運行。 定時器代碼最早能執行的時機是在 300ms 處,即 onclick 事件處理程序結束之后。 ~~~ ![](https://img.kancloud.cn/ae/b0/aeb0acd2213d7eec3e4f97ac318fabf5_516x165.png) ~~~ var btn = document.getElementById("my-btn"); btn.onclick = function(){ setTimeout(function(){ document.getElementById("message").style.visibility = "visible"; }, 250); //其他代碼 }; ~~~ >[danger] ##### 小技巧連續的定時器 ~~~ 1.setInterval() 是連續執行的定時器,這個會有一個弊端像下面圖一樣: 定時器是在 205ms 處添加到隊列中的,但是直到過了 300ms 處才能夠執行第一個定時器。當執行 這個定時器代碼時,在 405ms 處又給隊列添加了另外一個副本。在下一個間隔,即 605ms 處,第一 個定時器代碼仍在運行,同時在隊列中已經有了一個定時器代碼的實例。結果是,在這個時間點上的 定時器代碼不會被添加到隊列中。結果在 5ms 處添加的定時器代碼結束之后,405ms 處添加的定時器代碼 就立刻執行。 ~~~ ![](https://img.kancloud.cn/df/45/df45a3a3d3ad289ae0bd75261e62f910_484x190.png) * 使用鏈式setTimeout() 解決 ~~~ 1.每次函數執行的時候都會創建一個新的定時器。第二個 setTimeout()調用使用了 arguments.callee 來獲取對 當前執行的函數的引用,并為其設置另外一 個定時器。這樣做的好處是,在前一個定時器代碼執行完之前, 不會向隊列插入新的定時器代碼,確保 不會有任何缺失的間隔 ~~~ ~~~ setTimeout(function(){ //處理中 setTimeout(arguments.callee, interval); }, interval); ~~~ * 書中一個元素向右移動,當左坐標在 200 像素的時候停止的案例 ~~~ setTimeout(function(){ var div = document.getElementById("myDiv"); left = parseInt(div.style.left) + 5; div.style.left = left + "px"; if (left < 200){ setTimeout(arguments.callee, 50); } }, 50); ~~~ >[info] ## Promise 和 setTimeout 的執行順序 ~~~ 1.Promise 和 setTimeout 都是異步,都會被在特定時間添加到隊列中,那么到底誰會先執行? 2.首先要弄清'任務'和'微觀任務',在'setTimeout'章節已經可以知道因為'js是單線程的緣故'所以 他需要對執行'任務'進行類似隊列來決定他們的執行順序觸發時機,在任務中還有一種任務叫 '微觀任務(Microtasks)' ~~~ >[danger] ##### 一個說明的案例 ~~~ 1.下面代碼打印結果為'a,b,c,d',先打印'a'在打印'b' 因為代碼的先后執行順序先依次'a' 和'b' 但是'c' 和'd' 都是異步他們的先后執行顯而易見不會因為他們代碼執行順序先后而依次打印。 2.首先'Promise ':需要進行 io、等待或者其它異步操作的函數,不返回真實結果,而返回一'承諾', 函數的調用方可以在合適的時機,選擇等待這個承諾兌現(通過 Promise 的 then 方法的回調) 3.這里可以簡單的理解這兩個異步:'Promise 屬于我們說的微觀任務,setTimeout 屬于宏觀任務',因此 'Promise 永遠在隊列尾部添加微觀任務。setTimeout 等宿主 API,則會添加任務。'因此可以得到 一個結論'作為微觀任務的代表Promise這個異步會直接在特定情況下添加到對應隊列執行尾部', 'setTimeout 則會根據調用他的宿主api執行了才把自己放到尾部' 4.因此'Promise 會比setTimeout先執行' ~~~ ~~~ var r = new Promise(function(resolve, reject){ console.log("a"); resolve() }); setTimeout(()=>console.log("d"), 0) r.then(() => console.log("c")); console.log("b") ~~~ >[danger] ##### 再來一個極端的案例接著說明 ~~~ 1.我們延遲Promise執行時間,增加到1s,這時候打印結果如果按照我們的猜想,即使'Promise'延遲了 你'setTimeout'也要排在我的后面,因為我'Promise' 就是比你先進隊列的不服你也給等著'我微觀任務' 就是牛逼因此打印結果'c1 c2 d' 2.根據' 極客時間 winter老師的總結'這里要說明 2.1.首先我們分析有多少個宏任務; 2.2.在每個宏任務中,分析有多少個微任務;根據調用次序,確定宏任務中的微任務執行次序; 2.3.根據宏任務的觸發規則和調用次序,確定宏任務的執行次序; 2.4.確定整個順序。 ~~~ ~~~ setTimeout(()=>console.log("d"), 0) var r = new Promise(function(resolve, reject){ resolve() }); r.then(() => { var begin = Date.now(); while(Date.now() - begin < 1000); console.log("c1") new Promise(function(resolve, reject){ resolve() }).then(() => console.log("c2")) }); ~~~ * 一個很有意思的屬性'MutationObserver' >[danger] ##### 總結 ~~~ 1.不同隊列優先級不同,每次事件循環時會從優先級高的隊列中獲取事件,只有當優先級高的隊列為空 時才會從優先級低的隊列中獲取事件,同級隊列之間的事件不存在優先級,只遵循先進先出的原則 process.nextTick(Node.js) > MutationObserver(瀏覽器)/promise.then(catch、finnally)> setImmediate(IE) > setTimeout/setIntervalrequestAnimationFrame > 其他 I/O 操作 / 瀏覽器 DOM 事件 2.一次 Eventloop 循環會處理一個宏任務和所有這次循環中產生的微任務。 2.1.macrotasks(宏任務): script(整體代碼),setTimeout,setInterval,setImmediate,I/O,UI rendering,event listner 2.2.microtasks(微任務): process.nextTick, Promises, Object.observe, MutationObserver ~~~ [參考文章 拉鉤](https://kaiwu.lagou.com/course/courseInfo.htm?courseId=180#/detail/pc?id=3180)
                  <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>

                              哎呀哎呀视频在线观看