目标: 实现fiber架构
如何控制dom树的渲染
- 期望每一次渲染一个dom,实现完成之后检测还剩下多少空余时间,如果足够渲染另一个dom
- 我们通过链表来实现,1. 找child节点 2. 找sibling节点 3. 找叔叔节点,具体规则可以参考下图。

实现代码的两种方案
- 先把树全部转成链表
- 可以边转链表,边去渲染,此方案更优,我们也是来实现此种方案,变构建关系,边渲染
把上节课中实现的任务调度器拷贝到react.js中和修改render
function workLoop(deadline) {
let shouldYield = false
while (!shouldYield && nextWorkOfUnit) {
nextWorkOfUnit = performWorkOfUnit(nextWorkOfUnit)
shouldYield = deadline.timeRemaining() < 1
}
requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
let nextWorkOfUnit = null
function render(el, container) {
nextWorkOfUnit = {
dom: container,
props: {
children: [el]
}
}
}
function performWorkOfUnit(work) {
if (!work.dom) {
const dom = (work.dom = work.type === "TEXT_ELEMENT" ?
document.createTextNode("") :
document.createElement(work.type));
work.parent.dom.append(dom)
Object.keys(work.props).forEach((key) => {
if (key !== "children") {
dom[key] = work.props[key];
}
});
}
const children = work.props.children
let prevChild = null
children.forEach((child, index) => {
const newWork = {
type: child.type,
props: child.props,
child: null,
parent: work,
sibling: null,
dom: null
}
if (index === 0) {
work.child = newWork
} else {
prevChild.sibling = newWork
}
prevChild = newWork
})
if (work.child) {
return work.child
}
if (work.sibling) {
return work.sibling
}
return work.parent?.sibling
}
优化并重构封装代码,将work重命名成fiber
function workLoop(deadline) {
let shouldYield = false
while (!shouldYield && nextWorkOfUnit) {
nextWorkOfUnit = performWorkOfUnit(nextWorkOfUnit)
shouldYield = deadline.timeRemaining() < 1
}
requestIdleCallback(workLoop)
}
function createDom(type) {
return type === "TEXT_ELEMENT" ?
document.createTextNode("") :
document.createElement(type);
}
function updateProps(dom, props) {
Object.keys(props).forEach((key) => {
if (key !== "children") {
dom[key] = props[key];
}
});
}
function initChildren(fiber) {
const children = fiber.props.children
let prevChild = null
children.forEach((child, index) => {
const newFiber = {
type: child.type,
props: child.props,
child: null,
parent: fiber,
sibling: null,
dom: null
}
if (index === 0) {
fiber.child = newFiber
} else {
prevChild.sibling = newFiber
}
prevChild = newFiber
})
}
function performWorkOfUnit(fiber) {
if (!fiber.dom) {
const dom = createDom(fiber.type)
fiber.dom = dom
fiber.parent.dom.append(dom)
updateProps(dom, fiber.props)
}
initChildren(fiber)
if (fiber.child) {
return fiber.child
}
if (fiber.sibling) {
return fiber.sibling
}
return fiber.parent?.sibling
}
requestIdleCallback(workLoop)