






















const box = document.body.querySelector(".box");
let start;
function animate(time) {
if (!start) start = time;
const progress = time - start;
console.log("当前时间戳 time:>> ", time);
const x = Math.min(progress * 0.1, 300);
box.style.transform = `translateX(${x}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
setTimeout(() => console.log("timeout"), 0);
const { port1, port2 } = new MessageChannel();
port1.onmessage = () => console.log("messagechannel");
port2.postMessage(null);
const s = performance.now();
console.log("before :>> ", s);
for (let index = 0; index < 100000; index++) {
const li = document.createElement("li");
li.innerHTML = index;
document.body.appendChild(li);
}
const e = performance.now();
const gap = performance.now();
console.log("after:>> ", performance.now());
console.log("gap:>> ", e - s); // 40ms左右
function workLoop() {
// 看看有没有下个工作,和时间够不够用了。一般就是5ms
while (nextUnitOfWork && !shouldYield()) {
// 有下个工作,并且还有时间, 执行工作。
// 并获取到再下个工作
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
if (nextUnitOfWork) {
// 这里是没有时间了,有下个工作了
// 时间片耗尽,放到下一个宏任务继续
scheduleCallback(workLoop);
} else {
// 没有下个工作了。
// 全部完成,可以 commit
commitRoot();
}
}
function performUnitOfWork(unit) {
// 做具体渲染逻辑(比如更新函数组件,创建 DOM 节点)
// 这个过程很快,通常 < 1ms
/**
* 执行函数组件,获得新的dom结构,函数组件就是在这里执行!
* 获取到新的state,props,context等, 记录这些的变化。
*/
const next = beginWork(unit);
// 每做完一个 fiber,就可以中断
if (!next) {
// 工作完成了,开始向上收集整个fiber树
completeUnitOfWork(unit);
}
return next;
}
function shouldYield() {
return performance.now() >= deadline;
}
let channel = new MessageChannel();
let taskQueue = [];
// 这个lock的目的是为了避免异步操作过程中,
/**
* 比如中断执行了,我们推入了一个函数。
* 这个时候,交处浏览器的主线程。
* 等浏览器执行完成后,会执行一个onmessage。
* 会再次进行咱们的workLoop.
*
* 但如果在浏览器执行过程中,有变化。比如,数据更新,上一次useEffect更新。或者点击啥的。
*
* 这个锁就是为了避免重复被安排。一次只安排一个。
* 可能会造成,连续发送两次postMessage. 会可能重复执行workLoop
*/
let isScheduled = false;
function scheduleCallback(callback) {
taskQueue.push(callback);
if (!isScheduled) {
isScheduled = true;
channel.port1.postMessage(null); // 触发异步执行
}
}
// 注册 port1 的消息处理器(作为“调度器入口”)
channel.port2.onmessage = () => {
isScheduled = false;
const callback = taskQueue.shift();
if (callback) {
callback(); // 继续执行 workLoop
}
};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。