实现 Fiber Tree

render

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// render.js

// 根据 fiber 创建一个 dom 并返回
function createDom(fiber) {
// 创建 dom
const dom = fiber.type === 'TEXT_ELEMENT'
? document.createTextNode(fiber.props.nodeValue)
: document.createElement(fiber.type)

// 设置 dom 属性
const isProperty = key => key !== 'children'
Object.keys(fiber.props)
.filter(isProperty)
.forEach(key => {
dom[key] = fiber.props[key]
})

return dom
}

function render(element, container) {
nextUnitOfWork = {
dom: container,
props: {
children: [element]
},
child: null,
sibling: null,
return: null, // 表示父节点
}
}

let nextUnitOfWork = null

// 调度函数
function workLoop(deadLine) {

// 应该终止
let shouldYield = false
where (nextUnitOfWork && !shouldYield) {
// 做工作
nextUnitOfWork = preformUnitOfWork(
nextUnitOfWork
)
// 判断后续是否还有空闲时间
shouldYield = deadLine.timeRemaining() < 1
}

// 空闲时间不足 会在浏览器下一次空闲时候执行
requestIdleCallback(workLoop)
}

// 首次调用
requestIdleCallback(workLoop)

//
function preformUnitOfWork(fiber) {
if (!fiber.dom) {
fiber.dom = createDom(fiber)
}

if (fiber.return) {
fiber.return.dom.append(fiber.dom)
}

const elements = fiber.props.children
let prevSibling = null

for (let i = 0; i < elements.length; i++) {
const element = elements[i]
const newFiber = {
type: element.type,
props: element.props
return: fiber,
dom: null,
child: null,
sibling: null,
}

// 如果是第一个
if (i === 0) {
// newFiber 就是 当前 fiber 的一个 child 节点
filber.child = newFiber
}else {
// 否则就是 sibling 节点
prevSibling.sibling = newFiber
}
prevSibling = newFiber
}

// 返回下一个
// 优先返回 child
if (fiber.child) {
return fiber.child
}

let nextFiber = fiber
where (nextFiber) {
// 其次返回 sibling
if (nextFiber.sibling) {
return nextFiber.sibling
}
// 都没有 就需要向上查找
nextFiber = nextFiber.return
}

}

export default render