返回

React调度机制之scheduleWork深度剖析(下)

前端

中断正在执行的任务

在React中,当一个高优先级的任务到来时,当前正在执行的任务可以被中断,以便优先执行高优先级的任务。这是通过scheduleCallbackForRoot()函数来实现的。

function scheduleCallbackForRoot(root, callback, expirationTime) {
  const updateExpirationTime = root.updateExpirationTime;
  if (expirationTime > updateExpirationTime) {
    root.updateExpirationTime = expirationTime;
    // ...
    if (isRendering) {
      // ...
      return;
    }
    // ...
  }
}

当一个高优先级的任务到来时,scheduleCallbackForRoot()函数首先会检查当前的updateExpirationTime是否小于高优先级任务的expirationTime。如果updateExpirationTime小于expirationTime,则将updateExpirationTime更新为expirationTime,并中断当前正在执行的任务。

中断当前任务后,scheduleCallbackForRoot()函数会将高优先级任务添加到任务队列中,等待调度。当调度器下次执行时,会优先执行高优先级任务。

继续中断的任务

在中断当前任务后,React会将中断的任务添加到任务队列中,等待调度。当调度器下次执行时,会继续执行中断的任务。

function continueWork(current, workInProgress, renderExpirationTime) {
  // ...
  if (workInProgress.expirationTime > renderExpirationTime) {
    // ...
    // 中断当前任务
    return;
  }
  // ...
}

当调度器继续执行中断的任务时,会首先检查任务的expirationTime是否大于当前的renderExpirationTime。如果expirationTime大于renderExpirationTime,则任务需要被中断,以便优先执行其他任务。否则,任务可以继续执行。

React16之前的setState()和React Fiber中的setState()的区别

在React16之前,当调用setState()时,React会将update添加到update队列中,然后等待update队列中的所有update都调度完后,才会执行render()函数。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  componentDidMount() {
    this.setState({ count: 1 });
    this.setState({ count: 2 });
    this.setState({ count: 3 });
  }

  render() {
    return (
      <div>
        {this.state.count}
      </div>
    );
  }
}

在上面的例子中,当调用componentDidMount()时,会依次调用三次setState(),将count的状态更新为1、2、3。但是,在React16之前,这些update都会被添加到update队列中,而不会立即执行。只有当update队列中的所有update都调度完后,才会执行render()函数,并将count的状态更新为3。

在React Fiber中,当调用setState()时,React会将update添加到update队列中,但是不会等待update队列中的所有update都调度完后,才会执行render()函数。相反,React Fiber会立即执行update队列中的第一个update,然后将剩余的update添加到update队列中,等待下次调度。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  componentDidMount() {
    this.setState({ count: 1 });
    this.setState({ count: 2 });
    this.setState({ count: 3 });
  }

  render() {
    return (
      <div>
        {this.state.count}
      </div>
    );
  }
}

在上面的例子中,当调用componentDidMount()时,会依次调用三次setState(),将count的状态更新为1、2、3。在React Fiber中,这些update都会被添加到update队列中,但是不会等待update队列中的所有update都调度完后,才会执行render()函数。相反,React Fiber会立即执行update队列中的第一个update,并将count的状态更新为1。然后,React Fiber会将剩余的两个update添加到update队列中,等待下次调度。

总结

在本文中,我们讨论了React调度机制中的scheduleWork()函数。我们了解了如何中断正在执行的任务,优先执行优先级比当前高的任务,以及如何在中断后继续之前的任务。此外,我们还比较了React16之前的setState()和React Fiber中的setState()的区别。