事件循环、宏任务、微任务一网打尽(附超多经典面试题)( 三 )


1.机制如下:
浏览器的事件循环 , 是在渲染进程中的;执行一个宏任务 , 栈中没有就从事件队列中获取;执行过程中如果遇到微任务 , 就添加到微任务的队列中;当前这个宏任务执行完毕后 , 立即执行当前微任务队列的所有微任务;当前宏任务执行完毕 , GUI线程接管渲染;渲染完毕后 , JS线程继续接管 , 开始下一个宏任务;
简化就两步:执行一个宏任务 , 执行完它对于的所有微任务;
事件循环、宏任务、微任务一网打尽(附超多经典面试题)
本文插图
2.浏览器渲染进程有三个异步队列

  • 宏任务macrotask/Tasks
  • 微任务Microtasks/Jobs
  • Animation callbacks:requestAnimationFrame也属于异步执行的方法 , 但该方法既不属于宏任务 , 也不属于微任务 。

(1)宏任务队列 , 每次循环只执行一个 。 设置 2 个相同时间的 timeout , 两个并不会一起执行 , 依然是分批的 。 (2)微任务队列 , 每次循环会把队列全部执行完才继续 。 因此如果任务本身又新增 Microtasks , 也会一直执行下去 。 所以下面的例子才会产生阻塞 。
(3)Animation callbacks队列 , 每次循环执行队列里的全部任务 , 连续调用两句 requestAnimationFrame , 会在同一次事件循环执行;但是任务本身又新增 Animation callback 是放到下一个循环执行 , 不会阻塞;(4)例题:
1)test1会导致执行栈溢出 , 因为所有的代码都在同步执行栈中 , 最大栈深度25000 , 溢出;2)test2 , 可以正常运行 , 因为把任务移到了宏任务队列中 , 没有阻塞主渲染线程;3)test3可以运行 , 但是会造成页面卡顿 , 因为微任务队列自身创建微任务 , 会不停创建执行、创建执行 , 虽然不会爆栈 , 但是阻塞了主线程 , 页面卡顿严重;
3.promise相关的经典面试题
(1)promise.then要等到resolve之后加入当前宏任务后面的微任务中;
  • 第一轮:宏任务1, 4;微任务:空
  • 第二轮:宏任务2;微任务:3
  • 第三轮:宏任务5 ,微任务:resolve了 , 把对应微任务加入~~7、8、9
  • 第四轮:6结果依次输出:1 4 2 3 5 7 8 9 6

(2)promise.then 中 return Promise.resolve, 会产生类似两轮的微任务
4的地方产生两轮微任务 , 所以3、7这一轮完了要再等两轮 , 再8、9之后输出输出结果:1、5、2、6、3、7、8、9、4、10
具体V8的底层原理 , 可以看知乎这一个问题
一.nodejs中事件循环和浏览器的异同
1.底层不同
一个基于浏览器;一个基于libuv库;放一个nodejs的系统架构图