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

requestWork #58

Open
Cosen95 opened this issue Oct 27, 2020 · 0 comments
Open

requestWork #58

Cosen95 opened this issue Oct 27, 2020 · 0 comments

Comments

@Cosen95
Copy link
Owner

Cosen95 commented Oct 27, 2020

requestWork

首先说明以下requestWork的核心功能:

  • root节点加入到root调度队列中
  • 判断是否是批量更新
  • 最后根据expirationTime的类型判断调度的类型

下面,我们来详细分析下requestWork的流程。首先来看requestWork

// requestWork is called by the scheduler whenever a root receives an update.
// It's up to the renderer to call renderRoot at some point in the future.
function requestWork(root: FiberRoot, expirationTime: ExpirationTime) {
  // 把当前 root设置为最高优先级
  addRootToSchedule(root, expirationTime);
  if (isRendering) {
    // 在render过程当中, 此时直接return
    // Prevent reentrancy. Remaining work will be scheduled at the end of
    // the currently rendering batch.
    return;
  }

  // 批量处理相关
  // 调用 setState 时在 enqueueUpdates 前 batchedUpdates 会把 isBatchingUpdates 设置成 true
  if (isBatchingUpdates) {
    // Flush work at the end of the batch.
    if (isUnbatchingUpdates) {
      // ...unless we're inside unbatchedUpdates, in which case we should
      // flush it now.
      nextFlushedRoot = root;
      nextFlushedExpirationTime = Sync;
      performWorkOnRoot(root, Sync, false);
    }
    return;
  }

  // TODO: Get rid of Sync and use current time?
  if (expirationTime === Sync) {
    // 同步的调用 js 代码
    performSyncWork();
  } else {
    // 异步调度 独立的 react 模块包,利用浏览器有空闲的时候进行执行,设置 deadline 在此之前执行
    scheduleCallbackWithExpirationTime(root, expirationTime);
  }
}

首先调用了addRootToSchedule

/**
 * 将 root 加入到调度队列
 *
 * @param {FiberRoot} root
 * @param {ExpirationTime} expirationTime
 */
function addRootToSchedule(root: FiberRoot, expirationTime: ExpirationTime) {
  // Add the root to the schedule.
  // Check if this root is already part of the schedule.

  // root.nextScheduledRoot 用来判断是否有异步任务正在调度, 为 null 时会增加 nextScheduledRoot
  // 这个 root 还没有进入过调度
  if (root.nextScheduledRoot === null) {
    // This root is not already scheduled. Add it.

    root.expirationTime = expirationTime;
    if (lastScheduledRoot === null) {
      // lastScheduledRoot firstScheduledRoot 是单向链表结构,表示多个 root 更新
      // 这里只有一个 root 只会在这里执行
      firstScheduledRoot = lastScheduledRoot = root;
      root.nextScheduledRoot = root;
    } else {
      // 有个多个root 时进行单向链表的插入操作
      lastScheduledRoot.nextScheduledRoot = root;
      lastScheduledRoot = root;
      lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
    }
  } else {
    // This root is already scheduled, but its priority may have increased.
    // 传入的 root 已经进入过调度, 把 root 的优先级设置最高
    const remainingExpirationTime = root.expirationTime;
    // 如果 root 的 expirationTime 是同步或者优先级低,增加为计算出的最高优先级
    if (expirationTime > remainingExpirationTime) {
      // Update the priority.
      // 把当前 root 的优先级设置为当前优先级最高的
      root.expirationTime = expirationTime;
    }
  }
}

作用比较清晰:

  • 判断当前root是否调度过, 单个或多个root构建成单向链表结构
  • 如果调度过,设置当前任务优先级最高

回到requestWork,分成了三个分支:

  • isRendering
  • isBatchingUpdates
  • expirationTime === Sync

我们来分别解释一下:

  • isRendering

isRendering 顾名思义在render过程当中, 此时直接返回return

batchedUpdate批处理的时候,将isRendering置成true,这样每次在执行setState时,都会走isRendering的分支直接返回,阻止更新,相当于暂停住,当第二个setState时依旧直接返回,避免出现频繁式的更新,也就是批处理。

  • isBatchingUpdates

isBatchingUpdates中又有一个isUnbatchingUpdates分支。isUnbatchingUpdates会在执行unbatchedUpdates()时设置为true。 也就是在首次渲染的时候不需要进行批处理,所以就会进行立即更新。 这里的两个变量名可能会造成误解,isBatchingUpdatesisUnbatchingUpdates这两个变量并不是互斥的,而是在两个方法中设置的哨兵变量。

如果是批处理的过程中的话,也会直接return

  • expirationTime === Sync

当前面的expirationTime被设置成了同步任务的时候,就会立即执行。 剩余的则会进入scheduleCallbackWithExpirationTime 通过ExpirationTime 进行调度。

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

No branches or pull requests

1 participant