1. import { setProps } from './utils';
    2. import {
    3. ELEMENT_TEXT, TAG_ROOT, TAG_HOST, TAG_TEXT, PLACEMENT
    4. } from './constants';
    5. let workInProgressRoot = null;//正在渲染中的根Fiber
    6. let nextUnitOfWork = null//下一个工作单元
    7. export function scheduleRoot(rootFiber) {
    8. //把当前树设置为nextUnitOfWork开始进行调度
    9. workInProgressRoot = rootFiber;
    10. nextUnitOfWork = workInProgressRoot;
    11. }
    12. function commitRoot() {
    13. let currentFiber = workInProgressRoot.firstEffect;
    14. while (currentFiber) {
    15. commitWork(currentFiber);
    16. currentFiber = currentFiber.nextEffect;
    17. }
    18. workInProgressRoot = null;
    19. }
    20. function commitWork(currentFiber) {
    21. if (!currentFiber) {
    22. return;
    23. }
    24. let returnFiber = currentFiber.return;//先获取父Fiber
    25. const domReturn = returnFiber.stateNode;//获取父的DOM节点
    26. if (currentFiber.effectTag === PLACEMENT && currentFiber.stateNode != null) {//如果是新增DOM节点
    27. let nextFiber = currentFiber;
    28. domReturn.appendChild(nextFiber.stateNode);
    29. }
    30. currentFiber.effectTag = null;
    31. }
    32. function performUnitOfWork(currentFiber) {
    33. beginWork(currentFiber);//开始渲染前的Fiber,就是把子元素变成子fiber
    34. if (currentFiber.child) {//如果子节点就返回第一个子节点
    35. return currentFiber.child;
    36. }
    37. while (currentFiber) {//如果没有子节点说明当前节点已经完成了渲染工作
    38. completeUnitOfWork(currentFiber);//可以结束此fiber的渲染了
    39. if (currentFiber.sibling) {//如果它有弟弟就返回弟弟
    40. return currentFiber.sibling;
    41. }
    42. currentFiber = currentFiber.return;//如果没有弟弟让爸爸完成,然后找叔叔
    43. }
    44. }
    45. function beginWork(currentFiber) {
    46. if (currentFiber.tag === TAG_ROOT) {//如果是根节点
    47. updateHostRoot(currentFiber);
    48. } else if (currentFiber.tag === TAG_TEXT) {//如果是原生文本节点
    49. updateHostText(currentFiber);
    50. } else if (currentFiber.tag === TAG_HOST) {//如果是原生DOM节点
    51. updateHostComponent(currentFiber);
    52. }
    53. }
    54. function updateHostRoot(currentFiber) {//如果是根节点
    55. const newChildren = currentFiber.props.children;//直接渲染子节点
    56. reconcileChildren(currentFiber, newChildren);
    57. }
    58. function updateHostText(currentFiber) {
    59. if (!currentFiber.stateNode) {
    60. currentFiber.stateNode = createDOM(currentFiber);//先创建真实的DOM节点
    61. }
    62. }
    63. function updateHostComponent(currentFiber) {//如果是原生DOM节点
    64. if (!currentFiber.stateNode) {
    65. currentFiber.stateNode = createDOM(currentFiber);//先创建真实的DOM节点
    66. }
    67. const newChildren = currentFiber.props.children;
    68. reconcileChildren(currentFiber, newChildren);
    69. }
    70. function createDOM(currentFiber) {
    71. if (currentFiber.type === ELEMENT_TEXT) {
    72. return document.createTextNode(currentFiber.props.text);
    73. }
    74. const stateNode = document.createElement(currentFiber.type);
    75. updateDOM(stateNode, {}, currentFiber.props);
    76. return stateNode;
    77. }
    78. function reconcileChildren(currentFiber, newChildren) {
    79. let newChildIndex = 0;//新虚拟DOM数组中的索引
    80. let prevSibling;
    81. while (newChildIndex < newChildren.length) {
    82. const newChild = newChildren[newChildIndex];
    83. let tag;
    84. if (newChild && newChild.type === ELEMENT_TEXT) {
    85. tag = TAG_TEXT;//文本
    86. } else if (newChild && typeof newChild.type === 'string') {
    87. tag = TAG_HOST;//原生DOM组件
    88. }
    89. let newFiber = {
    90. tag,//原生DOM组件
    91. type: newChild.type,//具体的元素类型
    92. props: newChild.props,//新的属性对象
    93. stateNode: null,//stateNode肯定是空的
    94. return: currentFiber,//父Fiber
    95. effectTag: PLACEMENT,//副作用标识
    96. nextEffect: null
    97. }
    98. if (newFiber) {
    99. if (newChildIndex === 0) {
    100. currentFiber.child = newFiber;//第一个子节点挂到父节点的child属性上
    101. } else {
    102. prevSibling.sibling = newFiber;
    103. }
    104. prevSibling = newFiber;//然后newFiber变成了上一个哥哥了
    105. }
    106. prevSibling = newFiber;//然后newFiber变成了上一个哥哥了
    107. newChildIndex++;
    108. }
    109. }
    110. function updateDOM(stateNode, oldProps, newProps) {
    111. setProps(stateNode, oldProps, newProps);
    112. }
    113. function completeUnitOfWork(currentFiber) {
    114. const returnFiber = currentFiber.return;
    115. if (returnFiber) {
    116. if (!returnFiber.firstEffect) {
    117. returnFiber.firstEffect = currentFiber.firstEffect;
    118. }
    119. if (!!currentFiber.lastEffect) {
    120. if (!!returnFiber.lastEffect) {
    121. returnFiber.lastEffect.nextEffect = currentFiber.firstEffect;
    122. }
    123. returnFiber.lastEffect = currentFiber.lastEffect;
    124. }
    125. const effectTag = currentFiber.effectTag;
    126. if (effectTag) {
    127. if (!!returnFiber.lastEffect) {
    128. returnFiber.lastEffect.nextEffect = currentFiber;
    129. } else {
    130. returnFiber.firstEffect = currentFiber;
    131. }
    132. returnFiber.lastEffect = currentFiber;
    133. }
    134. }
    135. }
    136. function workLoop(deadline) {
    137. let shouldYield = false;
    138. while (nextUnitOfWork && !shouldYield) {
    139. nextUnitOfWork = performUnitOfWork(nextUnitOfWork);//执行一个任务并返回下一个任务
    140. shouldYield = deadline.timeRemaining() < 1;//如果剩余时间小于1毫秒就说明没有时间了,需要把控制权让给浏览器
    141. }
    142. //如果没有下一个执行单元了,并且当前渲染树存在,则进行提交阶段
    143. if (!nextUnitOfWork && workInProgressRoot) {
    144. commitRoot();
    145. }
    146. requestIdleCallback(workLoop);
    147. }
    148. //开始在空闲时间执行workLoop
    149. requestIdleCallback(workLoop);