Skip to content

[Note] 渲染时的优化策略 #12

@ddzy

Description

@ddzy

1. 遍历 Fiber Tree 时的优化

react每产生一个更新, 都会遍历整个Fiber Tree, 这样做会产生很大的性能开销, 所以就需要采取必要的优化措施.

beginWork 方法内部, 分别进行了两个方面的优化:

  1. props 是否改变?
if (oldProps !== newProps || hasLegacyContextChanged()) {
      // If props or context changed, mark the fiber as having performed work.
      // This may be unset if the props are determined to be equal later (memo).
      didReceiveUpdate = true;
 }

react通过比对当前遍历到的fiber节点的新旧props是否相等, 来计算当前节点是否需要在当前的更新批次中更新.

  1. 当前节点是否有挂起的更新?
else if (updateExpirationTime < renderExpirationTime) {
      didReceiveUpdate = false;

      return bailoutOnAlreadyFinishedWork(
        current,
        workInProgress,
        renderExpirationTime,
      );
}

如果当前的fiber节点产生的更新的优先级小于当前整体更新流程的优先级, 代表当前节点不需要更新, 继续检查当前节点的子树是否需要更新.

  1. 当前节点的子树有否有挂起的更新
function bailoutOnAlreadyFinishedWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
): Fiber | null {
  // Check if the children have any pending work.
  const childExpirationTime = workInProgress.childExpirationTime;

  if (childExpirationTime < renderExpirationTime) {
    // The children don't have any work either. We can skip them.
    // TODO: Once we add back resuming, we should check if the children are
    // a work-in-progress set. If so, we need to transfer their effects.
    return null;
  } else {
    // This fiber doesn't have work, but its subtree does. Clone the child
    // fibers and continue.
    cloneChildFibers(current, workInProgress);
    return workInProgress.child;
  }
}

bailoutOnAlreadyFinishedWork内部, 会检查当前fiber节点的子树是否有挂起的更新:

  • 如果没有, 或者子树的更新优先级较小: 终止当前的整体遍历流程
  • 反之: 克隆其子树, 复用节点

Metadata

Metadata

Assignees

No one assigned

    Labels

    note简单笔记

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions