深入理解 JavaScript 之事件循环(Event Loop),总结2024年180道前端岗面试题
时间:2024-04-07 13:45:26 来源:网络cs 作者:璐璐 栏目:防关联工具 阅读:
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’)
整体 script 作为第一个宏任务进入主线程,输出script start
遇到 setTimeout,setTimeout 为宏任务,加入宏任务队列
遇到 Promise,其 then 回调函数加入到微任务队列;第二个 then 回调函数也加入到微任务队列
继续往下执行,输出script end
检测微任务队列,输出promise1、promise2
进入下一轮循环,执行 setTimeout 中的代码,输出setTimeout
最后执行结果为:
script startscript endpromise1promise2setTimeout
经典题目 2
来看一道面试的经典题目
async function async1() { console.log(‘async1 start’) await async2() console.log(‘async1 end’)}async function async2() { console.log(‘async2’)}console.log(‘script start’)setTimeout(function () { console.log(‘setTimeout’)}, 0)async1()new Promise(function (resolve) { console.log(‘promise1’) resolve()}).then(function () { console.log(‘promise2’)})console.log(‘script end’)
整体 script 作为第一个宏任务进入主线程,代码自上而下执行,执行同步代码,输出 script start
遇到 setTimeout,加入到宏任务队列
执行 async1(),输出async1 start;然后遇到await async2(),await 实际上是让出线程的标志,首先执行 async2(),输出async2;把 async2() 后面的代码console.log(‘async1 end’)加入微任务队列中,跳出整个 async 函数。(async 和 await 本身就是 promise+generator 的语法糖。所以 await 后面的代码是微任务。)
继续执行,遇到 new Promise,输出promise1,把.then()之后的代码加入到微任务队列中
继续往下执行,输出script end。接着读取微任务队列,输出async1 end,promise2,执行完本轮的宏任务。继续执行下一轮宏任务的代码,输出setTimeout
最后执行结果为:
script startasync1 startasync2promise1script endasync1 endpromise2setTimeout
经典题目 3
我们来看下面一段代码:
setTimeout(function () { console.log(‘timer1’)}, 0)
requestAnimationFrame(function () { console.log(‘requestAnimationFrame’)})
setTimeout(function () { console.log(‘timer2’)}, 0)
new Promise(function executor(resolve) { console.log(‘promise 1’) resolve() console.log(‘promise 2’)}).then(function () { console.log(‘promise then’)})
console.log(‘end’)
整体 script 代码执行,开局新增三个宏任务,两个 setTimeout 和一个 requestAnimationFrame
遇到 Promise,先输出promise1, promise2,加把 then 回调加入微任务队列。
继续往下执行,输出end
执行 promise 的 then 回调,输出promise then
接下来剩三个宏任务,我们可以知道的是timer1会比timer2先执行,那么requestAnimationFrame呢?
当每一轮事件循环的微任务队列被清空后,有可能发生 UI 渲染,也就是说执行任务的耗时会影响视图渲染的时机。
通常浏览器以每秒 60 帧(60fps)的速率刷新页面,这个帧率最适合人眼交互,大概 1000ms/60 约等于 16.7ms 渲染一帧,如果要让用户看得顺畅,单个宏任务及它相应的微任务最好能在 16.7ms 内完成。
requestAnimationFrame 是什么?
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
requestAnimationFrame 的基本思想是 让页面重绘的频率和刷新频率保持同步,相比 setTimeout,requestAnimationFrame 最大的优势是由系统来决定回调函数的执行时机。
但这个也不是每轮事件循环都会执行 UI 渲染,不同浏览器有自己的优化策略,比如把几次的视图更新累积到一起重绘,重绘之前会通知 requestAnimationFrame 执行回调函数,也就是说 requestAnimationFrame 回调的执行时机是在一次或多次事件循环的 UI render 阶段。
在我的谷歌浏览器执行结果:
promise 1promise 2endpromise thenrequestAnimationFrametimer1timer2
在我的火狐浏览器执行结果:
promise 1promise 2endpromise thentimer1timer2requestAnimationFrame
谷歌浏览器中的结果 requestAnimationFrame()是在一次事件循环后执行,火狐浏览器中的结果是在三次事件循环结束后执行。
可以知道,浏览器只保证 requestAnimationFrame 的回调在重绘之前执行,但没有确定的时间,何时重绘由浏览器决定。
参考文章
JavaScript 中的 Event Loop(事件循环)机制
- EOF -
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
最后
正值招聘旺季,很多小伙伴都询问我有没有前端方面的面试题!
CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-8Brqlwsu-1711868798064)]
最后
正值招聘旺季,很多小伙伴都询问我有没有前端方面的面试题!
CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
本文链接:https://www.kjpai.cn/news/2024-04-07/155152.html,文章来源:网络cs,作者:璐璐,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!
下一篇:返回列表