哈喽!你们好!我是木瓜太香,我又来嘞,今天来讲说前端面试中常常别问到的 JS 事件环问题。javascript
JS 程序的运行是离不开事件环机制的,这个机制保证在发生某些事情的时候咱们有机会执行一个咱们事先预约好的函数,事情发生的时候 JS 会将相应的函数入栈执行而后出栈,可是关于事件环咱们还有一些未知的东西,例如,setTimeout 咱们习惯称他为定时器,可是可能不少人没有意识到,这个东西和咱们经常使用的一些事件没什么不一样,只不过咱们一般所说的事件大多须要用户触发,而 setTimeout 不用用户本身触发,而是指定时间以后触发;那么问题来了,若是咱们将时间设置为 0 会发生什么?会当即执行么?html
setTimeout、DOM或者 HTTP请求这部分其实并不在 v8 引擎中,这些属于 web API,javascript 是一个单线程的语言,也就意味着一次只能作一件事情,这个事实从未改变前端
JS 中全部的方法都会被推入栈中执行,执行完成被弹出,在遇到异步代码的时候,例如 setTimeout MutationObserver Promise 异步的部分会由其余掌管 webAPI 的地方执行,等异步有结果以后,回调函数会进入相应的队列,Promise MutationObserver 回调进入微任务队列,setTimeout setInterval requestAnimationFrame 进入宏任务队列。等待主线程的执行栈空了,微任务队列马上被推入栈中执行,执行完毕开始执行宏任务队列java
htmlweb
<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
元素的时候会有以下输出chrome
click promise mutate click promise mutate timeout timeout
截止 2020年8月份 chrome edge opera firefox 的结果是统一的,可是在此以前的版本可能会有不一样的输出。promise
上述代码咱们不使用手动触发点击,而是使用 inner.click()
触发点击,其结果会有很大的不一样浏览器
click click promise mutate promise timeout timeout
形成以上巨大差别的缘由是,手动点击,不是经过函数进入执行栈的方式触发点击事件的回调,因此inner 的回调执行完了主线程中的执行栈就是空的能够直接执行队列中任务,而后事件冒泡致使的回调函数才被推入栈运行;而 click 方法的点击则是经过将 click 推入栈中执行来达到的,inner 的点击回调执行完了以后 click 方法并无被弹出栈,而是直接执行冒泡的下一个回调,因为下一个回调有一个重复的 属性设置 这是不会重复触发 MutationObserver的因此 mutate 的输出只会有一个。等全部的冒泡回调被执行完毕 click 函数才会被弹出栈。dom
最后注意,浏览器会尽可能预先执行较为敏感的操做。
有前端问题须要讨论的能够加个人qun:237871108。也能够经过哔哩哔哩搜索木瓜太香找到我。