Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

调和 #6

Open
bibi7 opened this issue Nov 22, 2019 · 0 comments
Open

调和 #6

bibi7 opened this issue Nov 22, 2019 · 0 comments

Comments

@bibi7
Copy link
Owner

bibi7 commented Nov 22, 2019

这部分先暂停。。最近事情有点多
------------------------------------break------------------------------------

调度完之后是渲染部分,渲染部分又可以分为调和(renderRoot)和提交(completeRoot)两个阶段。
先看看调和吧,主要是renderRoot这个阶段,我发现这个函数在两个文件中都存在了,分别是:

  1. ReactFiberScheduler.old.js
  2. ReactFiberScheduler.new.js

具体有啥区别。。。?估计是保留了一下原先的版本?先看old的吧

// 开始渲染整颗树,这个函数在异步模式下可能会被多次执行,因为在异步模式下
// 可以打断任务。打断也就意味着每次都得回到 root 再开始从上往下循环
// 单这个函数就两百行。。删减大部分暂时不需要的部分
function renderRoot(
  root: FiberRoot,
  isYieldy: boolean,
  isExpired: boolean,
): void {
  isWorking = true;
  ReactCurrentOwner.currentDispatcher = Dispatcher;

  const expirationTime = root.nextExpirationTimeToWorkOn;

  // Check if we're starting from a fresh stack, or if we're resuming from
  // previously yielded work.
  if (
    expirationTime !== nextRenderExpirationTime ||
    root !== nextRoot ||
    nextUnitOfWork === null
  ) {
    // Reset the stack and start working from the root.
    resetStack();
    nextRoot = root;
    nextRenderExpirationTime = expirationTime;
    // 获取下一个需要工作的单元
    nextUnitOfWork = createWorkInProgress(
      // FiberRoot 对应的 Rootfiber
      nextRoot.current,
      null,
      nextRenderExpirationTime,
    );
    root.pendingCommitExpirationTime = NoWork;
    // ......
  }
  // ......
  do {
    try {
      // 循环更新节点
      workLoop(isYieldy);
    } catch (thrownValue) {
      // 遇到某种错误
    break;
  } while (true);

  // 这里有一大堆的错误处理
  
  // Ready to commit.
  onComplete(root, rootWorkInProgress, expirationTime);
}
  1. nextUnitOfWork = createWorkInProgress()我们不希望在当前的fibertree上直接修改,所以选择生成一个类似副本的东西,在上面做修改
  2. 将拷贝出来的nextUnitOfWork备份塞入workLoop
function workLoop(isYieldy) {
  // 对 nextUnitOfWork 循环进行判断,直到没有 nextUnitOfWork
  if (!isYieldy) {
    // 不可中断
    // Flush work without yielding
    while (nextUnitOfWork !== null) {
      // 一开始进来 nextUnitOfWork 是 root,每次执行 performUnitOfWork 后
      // 都会生成下一个工作单元
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  } else {
    // 可中断
    // Flush asynchronous work until the deadline runs out of time.
    while (nextUnitOfWork !== null && !shouldYield()) {
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  }
}

循环寻找工作单元的这个流程其实很简单,就是自顶向下再向上的一个循环。

  1. root 永远是第一个工作单元,不管之前有没有被打断过任务
  2. 首先判断当前节点是否存在第一个子节点,存在的话它就是下一个工作单元,并让下一个工作节点继3续执行该条规则,不存在的话就跳到规则 3
  3. 判断当前节点是否存在兄弟节点。如果存在兄弟节点,就回到规则 2,否则跳到规则 4
  4. 回到父节点并判断父节点是否存在。如果存在则执行规则 3,否则跳到规则 5
  5. 当前工作单元为 null,即为完成整个循环
  6. shouldYield()用来判断当前帧是否还有时间更新,有时间就更新,没有时间了就不更了。
// 开始组件更新
function performUnitOfWork(workInProgress: Fiber): Fiber | null {
  // The current, flushed, state of this fiber is the alternate.
  // Ideally nothing should rely on this, but relying on it here
  // means that we don't need an additional field on the work in
  // progress.
  // 获得 fiber 的替身,调和这一阶段都是在替身上完成的
  // 然后直接看 beginWork
  const current = workInProgress.alternate;

  // ......
  let next;

  // .....
  // 开始工作
  next = beginWork(current, workInProgress, nextRenderExpirationTime);
  workInProgress.memoizedProps = workInProgress.pendingProps;

  // ......

  // 当前fiber树已经更新到叶子节点了
  if (next === null) {
    // If this doesn't spawn new work, complete the current work.
    next = completeUnitOfWork(workInProgress);
  }

  ReactCurrentOwner.current = null;

  return next;
}

beginWork就更长了,主要是根据不同的workInProgress来进行不同的处理方式
比如class组件,比如文本节点,比如函数式组件,有大量的switch case操作。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant