哈嘍!大家好!我是木瓜太香,我又來嘞,今天來說說前端面試中經常別問到的 JS 事件環問題,
JS 事件環
JS 程式的運行是離不開事件環機制的,這個機制保證在發生某些事情的時候我們有機會執行一個我們事先預定好的函式,事情發生的時候 JS 會將相應的函式入堆疊執行然后出堆疊,但是關于事件環我們還有一些未知的東西,例如,setTimeout 我們習慣稱他為定時器,但是可能很多人沒有意識到,這個東西和我們常用的一些事件沒什么不同,只不過我們通常所說的事件大多需要用戶觸發,而 setTimeout 不用用戶自己觸發,而是指定時間之后觸發;那么問題來了,如果我們將時間設定為 0 會發生什么?會立即執行么?
setTimeout、DOM或者 HTTP請求這部分其實并不在 v8 引擎中,這些屬于 web API,javascript 是一個單執行緒的語言,也就意味著一次只能做一件事情,這個事實從未改變
執行原理
JS 中所有的方法都會被推入堆疊中執行,執行完成被彈出,在遇到異步代碼的時候,例如 setTimeout MutationObserver Promise 異步的部分會由其他掌管 webAPI 的地方執行,等異步有結果之后,回呼函式會進入相應的佇列,Promise MutationObserver 回呼進入微任務佇列,setTimeout setInterval requestAnimationFrame 進入宏任務佇列,等待主執行緒的執行堆疊空了,微任務佇列立刻被推入堆疊中執行,執行完畢開始執行宏任務佇列

一個經典的例子
html
<div class="outer">
<div class="inner"></div>
</div>
js
// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
// Let's listen for attribute changes on the
// outer element
new MutationObserver(function () {
console.log('mutate');
}).observe(outer, {
attributes: true,
});
// Here's a click listener…
function onClick() {
console.log('click');
setTimeout(function () {
console.log('timeout');
}, 0);
Promise.resolve().then(function () {
console.log('promise');
});
outer.setAttribute('data-random', Math.random());
}
// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
以上代碼在,手動點擊 inner 元素的時候會有如下輸出
click
promise
mutate
click
promise
mutate
timeout
timeout
截止 2020年8月份 chrome edge opera firefox 的結果是統一的,但是在此之前的版本可能會有不同的輸出,
一個奇怪的現象
上述代碼我們不使用手動觸發點擊,而是使用 inner.click() 觸發點擊,其結果會有很大的不同
click
click
promise
mutate
promise
timeout
timeout
造成以上巨大差異的原因是,手動點擊,不是通過函式進入執行堆疊的方式觸發點擊事件的回呼,所以inner 的回呼執行完了主執行緒中的執行堆疊就是空的可以直接執行佇列中任務,然后事件冒泡導致的回呼函式才被推入堆疊運行;而 click 方法的點擊則是通過將 click 推入堆疊中執行來達到的,inner 的點擊回呼執行完了之后 click 方法并沒有被彈出堆疊,而是直接執行冒泡的下一個回呼,由于下一個回呼有一個重復的 屬性設定 這是不會重復觸發 MutationObserver的所以 mutate 的輸出只會有一個,等所有的冒泡回呼被執行完畢 click 函式才會被彈出堆疊,
最后注意,瀏覽器會盡量預先執行較為敏感的操作,
有前端問題需要討論的可以加我的qun:237871108,也可以通過嗶哩嗶哩搜索木瓜太香找到我,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/4515.html
標籤:JavaScript
