如何 react 日程影响?我做了一些测试,似乎 hooks 是在 requestAnimationFrame 之后、setTimeout 之前调用的。所以我就想知道,scheduler的真正实现是怎样的?我检查了react源代码,它似乎是基于MessageChannel api构建的。 另外,事件循环如何运行宏任务序列,例如 setTimeout/script 等?
const addMessageChannel = (performWorkUntilDeadline: any) => {
const channel = new MessageChannel();
const port = channel.port2;
channel.port1.onmessage = performWorkUntilDeadline;
port.postMessage(null);
}
const Component1 = () => {
const [value,] = useState('---NOT INITIALISED')
requestIdleCallback(() => {
console.log('requestIdleCallback---')
})
useEffect(() => {
console.log('useEffect---')
}, [])
Promise.resolve().then(() => {
console.log('promise---')
})
setTimeout(() => {
console.log('setTimeout---')
});
addMessageChannel(()=> {
console.log('addMessageChannel---')
})
requestAnimationFrame(() => {
console.log('requestAnimationFrame---')
})
return <div>{value}</div>;
}
export default Component1
浏览器控制台结果:
promise---
requestAnimationFrame---
addMessageChannel---
useEffect---
setTimeout---
requestIdleCallback---
最佳答案
我不确定 useEffect
所以我会相信你的话,他们使用 MessageChannel 并考虑 addMessageChannel
和 useEffect
平局。
首先是标题(至少是一部分):
[Does] requestAnimationFrame belong to microtask or macrotask[...]?
从技术上讲……两者都不是。 requestAnimationFrame
(rAF) 的回调是...回调。
友情提醒,不存在“宏任务”这样的东西:有“tasks”和“microtasks”,后者是前者的子集。
现在,虽然微任务是任务,但它们确实有一个特殊的处理模型,因为它们确实有自己的微任务队列(不是任务队列),并且在每个事件循环迭代期间将被访问多次。有多个"microtask-checkpoints" event-loop processing model中定义,并且每次 JS 调用堆栈为空时,该微任务队列也会被访问。
还有一些任务,通俗地称为“宏任务”,以区别于微任务。每个 event-loop iteration 只会执行其中一个任务,在第一步中选择。
最后还有回调。这些可以从任务中调用(例如,当任务要触发事件时),或者在某些特定的事件循环迭代中调用,称为“绘画框架”。
事实上标记为 update the rendering 的步骤偶尔会被调用一次(一般是在显示器发送垂直同步更新时),并且会运行一系列操作,调用回调,其中就有我们亲爱的rAF的回调。
为什么这很重要?因为这意味着 rAF(以及“绘画框架”中的其他回调)在事件循环中具有特殊的位置,它们似乎以最高优先级被调用。实际上,它们本身并不参与任务优先级系统(这发生在事件循环的第一步),它们确实可以从相同的事件循环迭代中调用,甚至可以从对它们进行排队的任务中调用。
setTimeout(() => {
console.log("timeout 1");
requestAnimationFrame(() => console.log("rAF callback"));
const now = performance.now();
while(performance.now() - now < 1000) {} // lock the event loop
});
setTimeout(() => console.log("timeout 2"));
requestAnimationFrame(() => {
setTimeout(() => {
console.log("timeout 1");
requestAnimationFrame(() => console.log("rAF callback"));
});
setTimeout(() => console.log("timeout 2"));
});
虽然这看起来像是在绘画框架中调用我们的任务的特殊情况,但实际上很常见,因为 browsers have recently决定中断 rAF,当文档没有动画时,对 rAF 的第一次调用立即触发绘画框架。
因此,任何使用 rAF 的测试都应该在文档启动很久之后开始,并且 rAF 循环已经在后台运行...
好的,所以 rAF 结果可能是错误的。你的其他结果呢?
- 首先 promise ,是的。也不是任务优先级的一部分,如上所述,一旦 JS 调用堆栈为空,微任务队列就会被访问,作为 clean after running a script 的一部分步骤。
- rAF,侥幸。
addMessageChannel
,请参阅this answer我的。基本上,在 Chrome 中,这是由于setTimeout
的最小超时为1ms
,并且消息任务源的优先级高于超时任务源。setTimeout
目前在 Chrome 中具有 1 毫秒的最小延迟,并且优先级低于 MessageEvents,但在消息之前调用它仍然不会违反规范。requestIdleCallback
,这个有点复杂,但考虑到它将等待事件循环在一段时间内没有执行任何操作,因此它将是最后一个。
关于reactjs - requestAnimationFrame在主线程任务管理中属于microtask还是macrotask?如果不是,我们如何对这种渲染端任务进行分类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70995372/