您好,登錄后才能下訂單哦!
這篇文章主要講解了“JavaScript中的事件循環機制及其運行原理是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript中的事件循環機制及其運行原理是什么”吧!
javascript是單線程的非阻塞的腳本語言
單線程
只有一個主線程來處理任務。
非阻塞
JS引擎執行異步任務時,不會一直等待返回結果,主線程會掛起(pending)這個任務,繼續執行其他任務,當異步任務返回結果時,js將異步任務的callback放到任務隊列中,等到當前任務棧中的任務都執行完畢,處于閑置狀態的主線程按照隊列順序將隊首的calback函數加入到執行棧中,執行該函數的同步代碼,如果又遇到異步任務,再將其回調函數加入到隊列中–事件循環機制。
JS通常是非阻塞的,除了某些特殊情況,JS會停止代碼執行:alert, confirm, prompt
js的任務隊列分為同步任務和異步任務
同步任務
在主線程里執行,當瀏覽器第一遍過濾html文件的時候可以執行完;(在當前作用域直接執行的所有內容,包括執行的方法、new出來的對象)
異步任務
比較耗費時間與性能的,當瀏覽器執行到這些的時候會將其丟到異步任務隊列中,不會立即執行的任務
異步任務分為宏任務(macrotask) 和 微任務(microtask),執行的優先級不同
宏任務:script, setTimeout, setInterval, setImmeditate, T/O, UI rendering
微任務:process, nextTick, promise.then(), object.observe, MutationObserver, await, async
回調函數是微任務,會被加入微任務隊列,回調函數是宏任務,會被加入宏任務隊列,微任務優先級高于宏任務
Event loop過程
主線程開始執行一段代碼, 假設開始執行一個 script 標簽內的代碼,將代碼放入執行棧中執行,同步代碼優先執行,執行過程中,當遇到任務源時,判斷是宏任務還是微任務。
如果是宏任務,加入到宏任務隊列中,如果是微任務,加入到微任務隊列中。
同步代碼執行完成,執行棧空閑,檢查微任務隊列中是否有可執行任務,如果有,依次執行所有微任務隊列中的任務。如果沒有。當前任務執行結束。
DOM渲染。
檢查宏任務隊列是否有可執行的宏任務,如果有,取出隊列中最前面的那個宏任務,加入到執行棧中開始執行,然后重復前面步驟,直到宏任務隊列中所有任務執行結束
微任務在DOM渲染前觸發,宏任務在DOM渲染后觸發
代碼示例1
// 語句一 console.log(1); // 語句二 setTimeout(()=>{ console.log(2); },0); //語句三 Promise.resolve().then(()=>{ console.log(3); }) // 語句四 console.log(4);
//輸出順序
//1,4,3,2
代碼示例2
console.log("script start"); setTimeout(function () { console.log("setTimeout"); }, 0); Promise.resolve() .then(function () { console.log("promise1"); }) .then(function () { console.log("promise2"); }); console.log("script end");
代碼示例3
new Promise(…)中的代碼,也是同步代碼,會立即執行。只有then之后的代碼,才是異步執行的代碼
console.log("script start"); setTimeout(function () { console.log("timeout1"); }, 10); new Promise((resolve) => { console.log("promise1"); resolve(); setTimeout(() => console.log("timeout2"), 10); }).then(function () { console.log("then1"); }); console.log("script end");
代碼示例4
async 和 await 是 Generator 和 Promise 的語法糖。async 函數和普通函數一樣,只是表示這個函數里有異步操作的方法,并返回一個 Promise 對象
await后面的函數執行完畢時,await會產生一個微任務(Promise.then是微任務)。
// 等價 async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } // Promise 寫法 async function async1() { console.log("async1 start"); Promise.resolve(async2()).then(() => console.log("async1 end")); }
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } async1(); setTimeout(() => { console.log("timeout"); }, 0); new Promise(function (resolve) { console.log("promise1"); resolve(); }).then(function () { console.log("promise2"); }); console.log("script end");
代碼示例5
// 1. 開始執行 console.log(1) // 2. 打印 1 setTimeout(function () { // 6. 瀏覽器在 0ms 后,將該函數推入任務隊列 console.log(2) // 7. 打印 2 Promise.resolve(1).then(function () { // 8. 將 resolve(1) 推入任務隊列 9. 將 function函數推入任務隊列 console.log('ok') // 10. 打印 ok }) }) // 3.調用 setTimeout 函數,并定義其完成后執行的回調函數 setTimeout(function () { // 11. 瀏覽器 0ms 后,將該函數推入任務隊列 console.log(3) // 12. 打印 3 }) // 4. 調用 setTimeout 函數,并定義其完成后執行的回調函數 // 5. 主線程執行棧清空,開始讀取 任務隊列 中的任務 // output: 1 2 ok 3
代碼示例6
// 1. 開始執行 console.log(1) // 2. 打印 1 setTimeout(function () { // 6. 瀏覽器在 0ms 后,將該函數推入任務隊列 console.log(2) // 7. 打印 2 Promise.resolve(1).then(function () { // 8. 將 resolve(1) 推入任務隊列 9. 將 function函數推入任務隊列 console.log('ok') // 10. 打印 ok }) }) // 3.調用 setTimeout 函數,并定義其完成后執行的回調函數 setTimeout(function () { // 11. 瀏覽器 0ms 后,將該函數推入任務隊列 console.log(3) // 12. 打印 3 }) // 4. 調用 setTimeout 函數,并定義其完成后執行的回調函數 // 5. 主線程執行棧清空,開始讀取 任務隊列 中的任務 // output: 1 2 ok 3
代碼示例7
setTimeout(function(){ console.log('1') }); new Promise(function(resolve){ console.log('2'); resolve(); }).then(function(){ console.log('3') }); var timer; timer = setInterval(function(){ console.log('5'); clearInterval(timer); }); new Promise(function(resolve){ resolve(); }).then(function(){ console.log('6') }); console.log('4'); // 2,4,3,6,1,5
代碼示例8
Promise.resolve().then(()=>{ console.log('Promise1') setTimeout(()=>{ console.log('setTimeout2') },0) }); setTimeout(()=>{ console.log('setTimeout1') Promise.resolve().then(()=>{ console.log('Promise2') }) },0); console.log('start'); // start -> Promise1 -> setTimeout1 -> Promise2 - > setTimeout2
實例
<body> <div id="box"></div> <script src="./app.js"></script>s </body> //js const box = document.getElementById('box') box.innerHTML = '<P>我是后來插進去的內容</P>' console.log("1"); setTimeout( ()=>{ console.log("2"); alert("定時器執行了") },0 ) Promise.resolve().then(()=>{ console.log("3") alert("Promise執行了") }) console.log("4");
tip:從規范來看,microtask (微任務)優先于 macrotask(宏任務) 執行,所以如果有需要優先執行的邏輯,放入microtask 隊列會比 task 更早的被執行。
感謝各位的閱讀,以上就是“JavaScript中的事件循環機制及其運行原理是什么”的內容了,經過本文的學習后,相信大家對JavaScript中的事件循環機制及其運行原理是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。