课程名称: 破解JavaScript高级玩法
课程章节: “永动机”- 事件循环
主讲老师: Cloud
今天学习的内容包括:
宏任务,微任务和事件循环
async+await
async function async1() { console.log("async1 start"); await async2(); // .then() console.log("async1 end"); } async function async2() { console.log("async2"); } // new Promise(function(resolve, reject) { // resolve(undefined); // }) console.log("main start"); setTimeout(function () { console.log("setTimeout"); }); async1(); new Promise(function (resolve) { console.log("promise 构造"); resolve(); }).then(function () { console.log("promise then"); }); console.log("main end"); // 宏任务: // 微任务: /* 输出 */ // main start // async1 start // async2 // promise 构造 // main end // async1 end // promise then // setTimeout
Promise
//第一个promise Promise.resolve() .then(() => { console.log(1); }) .then(() => { console.log(3); return Promise.resolve(7); }) .then((res) => { console.log(res); }); //第二个promise Promise.resolve() .then(() => { console.log(2); }) .then(() => { console.log(4); }) .then(() => { console.log(5); }) .then(() => { console.log(6); }) .then(() => { console.log(8); });
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .outer-btn{ position: relative; width: 300px; height: 100px; background: red; } .inner-btn{ position: relative; width: 200px; height: 80px; background: yellow; } </style> </head> <body> <div class="outer-btn"> 外部按钮 <div class="inner-btn">内部按钮</div> </div> <script> var outerBtn = document.querySelector(".outer-btn"); var innerBtn = document.querySelector(".inner-btn"); new MutationObserver(function () { console.log("mutate 微任务"); }).observe(outerBtn, { //观察属性变化 attributes: true, }); //点击方法 function onClick() { console.log("click"); setTimeout(function () { console.log("timeout 宏任务"); }); Promise.resolve().then(function () { console.log("promise 微任务"); }); outerBtn.setAttribute("data-number", Math.random()); } outerBtn.addEventListener("click", onClick); innerBtn.addEventListener("click", onClick); // click时: // 宏任务队列:onClick(inner), onClick(outer) // 事件循环: 执行第一个onClick(inner) // 执行前: // 宏任务队列:onClick(inner), onClick(outer) // 微任务任务队列: //// console.log("click"); // 执行后: // 宏任务队列: onClick(outer), setTimeout // 微任务任务队列:promise, mutate //// 执行微任务输出: promise 微任务, mutate 微任务 //事件循环: 执行第二个onClick(outer) // 执行前: // 宏任务队列:onClick(outer), setTimeout // 微任务任务队列: //// console.log("click"); // 执行后: // 宏任务队列: setTimeout, setTimeout // 微任务任务队列:promise, mutate ///// 执行微任务输出: promise 微任务, mutate 微任务 // 下一个事件循环 // 执行前 宏任务队列: setTimeout, setTimeout //// 输出 timeout 宏任务 // 执行后 宏任务队列: setTimeout // 再下一个事件循环 // 执行前 宏任务队列: setTimeout //// 输出 timeout 宏任务 // 执行后 宏任务队列: </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .outer-btn{ position: relative; width: 300px; height: 100px; background: red; } .inner-btn{ position: relative; width: 200px; height: 80px; background: yellow; } </style> </head> <body> <div class="outer-btn"> 外部按钮 <div class="inner-btn">内部按钮</div> </div> <script> var outerBtn = document.querySelector(".outer-btn"); var innerBtn = document.querySelector(".inner-btn"); new MutationObserver(function () { console.log("mutate 微任务"); }).observe(outerBtn, { //观察属性变化 attributes: true, }); //点击方法 function onClick(ev) { console.log("click", ev.currentTarget.className); setTimeout(function () { console.log("timeout 宏任务"); }); Promise.resolve().then(function () { console.log("promise 微任务"); }); outerBtn.setAttribute("data-number", Math.random()); } outerBtn.addEventListener("click", onClick); innerBtn.addEventListener("click", onClick); // innerBtn.click(); // 执行第一个onClick(inner) // 执行前: // 宏任务队列: // 微任务任务队列: //// console.log("click"); // 执行后: // 宏任务队列: setTimeout // 微任务任务队列:promise, mutate // 执行第二个onClick(outer) // 执行前: // 宏任务队列:setTimeout // 微任务任务队列:promise, mutate //// console.log("click"); // 执行后:!!!! MutationObserver 不会再添加 // 宏任务队列: setTimeout, setTimeout // 微任务任务队列:promise, mutate, promise, ///// 执行微任务输出: promise 微任务, mutate 微任务,promise 微任务, // 下一个事件循环 // 执行前 宏任务队列: setTimeout, setTimeout //// 输出 timeout 宏任务 // 执行后 宏任务队列: setTimeout // 再下一个事件循环 // 执行前 宏任务队列: setTimeout //// 输出 timeout 宏任务 // 执行后 宏任务队列: </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .outer-btn{ position: relative; width: 300px; height: 100px; background: red; } .inner-btn{ position: relative; width: 200px; height: 80px; background: yellow; } </style> </head> <body> <div class="outer-btn"> 外部按钮 <div class="inner-btn">内部按钮</div> </div> <script> var outerBtn = document.querySelector(".outer-btn"); var innerBtn = document.querySelector(".inner-btn"); new MutationObserver(function () { console.log("mutate 微任务"); }).observe(outerBtn, { //观察属性变化 attributes: true, }); //点击方法 function onClick() { console.log("click"); setTimeout(function () { console.log("timeout 宏任务"); }); Promise.resolve().then(function () { console.log("promise 微任务"); }); outerBtn.setAttribute("data-number", Math.random()); } outerBtn.addEventListener("click", onClick); innerBtn.addEventListener("click", onClick); //点击 const evObj= document.createEvent("MouseEvents"); evObj.initEvent("click", true, true); evObj.eventType = 'message'; innerBtn.dispatchEvent(evObj); </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .outer-btn{ position: relative; width: 300px; height: 100px; background: red; } .inner-btn{ position: relative; width: 200px; height: 80px; background: yellow; } </style> </head> <body> <div class="outer-btn"> 外部按钮 </div> <script> var outerBtn = document.querySelector(".outer-btn"); new MutationObserver(function () { console.log("mutate 微任务"); }).observe(outerBtn, { //观察属性变化 attributes: true, }); //点击方法 function onClick() { console.log("click"); outerBtn.setAttribute("data-number", Math.random()); outerBtn.setAttribute("data-number", Math.random()); outerBtn.setAttribute("data-number", Math.random()); } outerBtn.addEventListener("click", onClick); </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .option-btn { position: relative; width: 200px; height: 200px; font-size: 20px; color: #fff; background: red; } </style> </head> <body> <div> <button id="btnStart">触发按钮</button> </div> <button class="first-btn">首次点击</button> <button class="second-btn"> 二次点击</button> <script> var firstBtn = document.querySelector(".first-btn"); var secondBtn = document.querySelector(".second-btn"); //同步耗时操作 function asyncSleep(duration) { const now = Date.now(); while (now + duration > Date.now()) { } } firstBtn.onclick = function () { console.log("firstBtn onClick", new Date().toLocaleTimeString()) //2. 假设需要执行3s console.time("firstBtn:cost") asyncSleep(3000); Promise.resolve().then(() => { console.log("执行 微任务 promise", new Date().toLocaleTimeString()); //3. 假设需要执行2s console.time("promise:cost"); asyncSleep(2000); console.timeEnd("promise:cost"); }) console.timeEnd("firstBtn:cost") } secondBtn.onclick = function () { console.log("secondBtn onClick", new Date().toLocaleTimeString()) //4. 假设需要执行1s console.time("secondBtn:cost") asyncSleep(1000); console.timeEnd("secondBtn:cost") } btnStart.onclick = function () { //1. 假设需要执行5s console.log("main:", new Date().toLocaleTimeString()) console.time("main:cost") asyncSleep(5000); console.timeEnd("main:cost") } </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> </style> </head> <body> <button id="btnLog" class="btnLog">操作点击事件</button> <button class="start">开始添加dom</button> <script> var startBtn = document.querySelector(".start"); var array = []; for (var i = 1; i <= 300000; i++) { array.push(i); //制造300000条数据 }; console.log("数据制造完成"); //渲染数据 var renderDomList = function (data) { for (var i = 0, l = data.length; i < l; i++) { var div = document.createElement('div'); div.innerHTML = `列表${i}`; document.body.appendChild(div); } }; startBtn.onclick = function () { console.log("startBtn clicked:", new Date().toLocaleTimeString()); renderDomList(array); } btnLog.onclick = function () { console.log("btnLog clicked:", new Date().toLocaleTimeString()); } </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> </style> </head> <body> <button id="btnLog" class="option-btn">操作点击事件</button> <button class="start">开始添加dom</button> <script> var startBtn = document.querySelector(".start"); const step = 200; var array = []; for (var i = 1; i <= 300000; i++) { array.push(i); //制造300000条数据 }; console.log("数据制造完成"); //渲染数据 var renderDomList = function (data, startIndex, endIndex) { if (startIndex < endIndex && endIndex <= data.length) { setTimeout(() => { for (let i = startIndex; i < endIndex; i++) { var div = document.createElement('div'); div.innerHTML = `列表${i}`; document.body.appendChild(div); } let nextIndex = endIndex + step > data.length ? data.length : endIndex + step; let nextStartIndex = endIndex > data.length ? data.length : endIndex; renderDomList(data, nextStartIndex, nextIndex); }, 0) } }; startBtn.onclick = function () { console.log("startBtn clicked:", new Date().toLocaleTimeString()); renderDomList(array, 0, 0 + step); } btnLog.onclick = function () { console.log("btnLog clicked:", new Date().toLocaleTimeString()); } </script> </body> </html>