如何应对日程影响?我做了一些测试,似乎 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
是平局。
首先是标题(至少部分):
[]requestAnimationFrame属于microtask还是macrotask[...]?
从技术上讲...都不是(参见标题“2024 更新”部分)。
requestAnimationFrame
(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"));
});
虽然这看起来像是在绘画框架中调用我们的任务的特殊情况,但实际上很常见,因为
浏览器最近决定打破rAF使对rAF的第一次调用立即触发绘画框架当文档没有动画时。
因此,任何使用 rAF 的测试都应该在文档启动很久之后开始,并且 rAF 循环已经在后台运行......
首先承诺,是的。也不是任务优先级的一部分,如上所述,一旦 JS 调用堆栈为空,微任务队列就会被访问,作为运行脚本后