嗨,我是你稳定输出、干货贼多的勾勾。
之前挂在菜单栏里的这道题目终于等到了答案!
题目:阅读下面代码,只考虑浏览器环境下的输出结果,写出结果打印的前后顺序,并说明具体原因。
console.log('AAAA')setTimeout(() => console.log('BBBB'), 1000)const start = new Date()while (new Date() - start < 3000) {}console.log('CCCC')setTimeout(() => console.log('DDDD'), 0)new Promise((resolve, reject) => { console.log('EEEE') foo.bar(100)}).then(() => console.log('FFFF')).then(() => console.log('GGGG')).catch(() => console.log('HHHH'))console.log('IIII')
答案解析:
浏览器下 输出结果的先后顺序是:
AAAACCCCEEEEIIIIHHHHBBBBDDDD
这道题考察重点是 JS 异步执行、宏任务、微任务。
在第一轮循环中,要处理完所有的同步代码,先逐行逐行的向下看。
第一行,console.log('AAAA') 这是一行同步代码,直接执行打印 AAAA。
第二行,setTimeout(),这个函数本身是同步的,但是它在 Web Api 中的任务是开启一个异步任务,且该任务是宏任务,规定 1 秒之后,该任务提交到任务队列。
第三行,const date = new Date() 没什么好说的。
第四行,一个 while 循环,且对本轮同步代码阻塞 3 秒。这里面需要考虑一个问题,就是上面的一个任务已经够 1 秒了,所以异步任务提交到任务队列了,由于本轮代码没有执行完毕,所以需要等待。
第五行,console.log('CCCC'),该行代码是同步代码,所以直接执行打印 CCCC。
第六行,setTimeout(()=>{console.log('DDDD')},0) ,这里 setTimeout() 这个函数是同步的,该函数就是开启一个宏任务,大概 0 秒后,提交到任务队列,但是当前任务队列中已经有个任务在排队,所以它排在该任务后面。
第七行,new Promise(()=>{console.log('EEEE')}) 这行代码 new Promise() 本身也是一个同步函数,它的作用就是开启一个异步任务,且这个任务是微任务,优先级高于宏任务,这个异步任务体现在 resolve 或 reject 上,也就是 then 后面的才是异步任务,所以 console.log('EEEE') 直接打印 EEEE。
由于函数内没有转入 resolve 状态,所以就执行 catch 后面的回调,这个微任务的优先级高于宏任务的优先级,所以要在任务队列中排在第一位。
第十四行,该行是个同步代码,所以直接打印 IIII。
到此,本轮代码执行完毕,剩下的就是通过 event loop 去任务队列查找任务,然后将其压入执行栈,按照任务队列的排列顺序,依次打印 HHHH BBBB DDDD。
综上,打印结果是 AAAA CCCC EEEE IIII HHHH BBBB DDDD。
学废了吗?下期每周一题我们再见:)
推荐阅读:
CRA 为什么要做成黑盒?
如何在 CRA 黑盒中争取主动权?
基操勿 6 | Node.js 的异步I/O到底有多秀?
前端跨平台桌面开发技术:Electron 快速起步
前端新玩具:Vite 及相关思考
效率提升利器:你还害怕自动化部署吗
JS 的内存管理与垃圾回收
点点“赞”和“在看”,保护头发,减少bug。