主线程
脚本作为任务的一部分,执行完成后浏览器才会开始渲染。 事件环可以确保你的任务在下一次渲染之前完成
requestAnimationFrame
setTimeout 移动速度快了3.5倍,表示回调被更频繁地调用。it is not a good thing
由浏览器决定什么时候渲染并且尽可能高效,只有值得更新才会渲染。
大多数情况下,页面会以固定频率更新,每秒60次。60hz是最常见的
如果我们一秒钟调用1000次渲染,页面也是每秒60次。仅渲染到显示器能够达到的频率,否则就是浪费时间,渲染的东西用户也看不到。
这就是setTimeout所做的,盒子移动速度更快,调用次数更多,多于用户所能看到的,也多于浏览器能够显示的。
setTimeout(callback, 0); 浏览器会选择任意数字 比如 setTimeout(callback, 4.7);
queueTask
每百分之二毫秒就得到一个新任务,所以render可以发生在任务之间,两次渲染之间可以有成千上万个任务。
假设这是显示给用户的帧图,浏览器的渲染。
发生在每个帧的开头,包括样式计算、布局和绘制,不一定三个都有。
事件环 基于加入队伍的事件,确保任务按顺序执行
就帧内的时间段而言,没有任何顺序
setTimeout 每帧会执行3-4个任务,这意味着3/4 都是不必要的,因为压根不会被渲染。
一些老的动画库会这么做,每秒执行60次
但是可能出现这种情况
如果使用requestAnimationFrame,一切都整洁有序,每一帧都顺序发生

requestAnimationFrame将动画打包起来,特别是已经有动画运行。这样会节省很多重复的工作
button.addEventListener('click', () => {box.style.transform = 'translateX(1000px)';box.style.transition = 'transform 1s ease-in-out';requestAnimationFrame(() => {requestAnimationFrame(() => {box.style.transform = 'translateX(500px)';})})})button.addEventListener('click', () => {box.style.transform = 'translateX(1000px)';box.style.transition = 'transform 1s ease-in-out';getComputedStyle(box).transform;box.style.transform = 'translateX(500px)';})

MicroTasks
90年代,浏览器想给开发者一种监控DOM变化的方法
如果微任务死循环,事件环会阻塞,直到微任务队列完全清空,这就是它阻止渲染的原因。
如果是用户点击button 结果:Listener1 Microtask1 1 1
如果是js执行 button.click() listener1 listener2 1 2
如果做自动化测试,使用JavaScript点击页面上元素,可能会得到不同的结果.
process a link click ,running the following steps:
1、Let eventObject be a new click event object
2、for each callback of link’s

先创建一个事件对象,然后调用每一个监听器,传入事件对象。
然后我们检查事件对象的canceled属性。如果canceled就不会打开链接,否则就打开。
当调用event.preventDefault() 时,事件会标记成canceled。
如果用户单击一个链接,那么我的微任务就会在每次回调后发生,因为JavaScript堆栈清空了。
但是当用JavaScript调用click时,他会执行完链接点击的操作。只有脚本完成后才会返回,因此JavaScript堆栈永远不会清空。
