美文网首页
React 中的 setState 是微任务还是宏任务

React 中的 setState 是微任务还是宏任务

作者: 前端小白的摸爬滚打 | 来源:发表于2021-08-10 13:22 被阅读0次

首先这个问法就表明 setState 是一个异步的任务

  1. 和 setTimeout 以及 Promise.then 做比较

首先在 React 的事件处理函数中 & React 的生命周期中 的 setState 是不会立即执行的,然后我们就发现 setState 执行完毕的时间是早于 Promise.then 的,但是这并不能证明他就是一个同步任务

handleClick = () => {
  const fans = Math.floor(Math.random() * 10)
  setTimeout(() => {
    console.log('宏任务触发')
  })
  Promise.resolve().then(() => {
    console.log('微任务触发')
  })
  this.setState({
    count: this.state.count + fans
  }, () => {
    console.log('新增粉丝数:', fans)
  })
}
  1. 和同步的 console.log 做对比
handleClick = () => {
  const fans = Math.floor(Math.random() * 10)
  console.log('开始运行')
  this.setState({
    count: this.state.count + fans
  }, () => {
    console.log('新增粉丝数:', fans)
  })
  console.log('结束运行')
}

结果

开始运行
结束运行
新增粉丝数: xxx

这么看,似乎 setState 又是一个异步的操作。主要原因是,在 React 的生命周期以及绑定的事件流中,所有的 setState 操作会先缓存到一个队列中,在整个事件结束后或者 mount 流程结束后,才会取出之前缓存的 setState 队列进行一次计算,触发 state 更新。只要我们跳出 React 的事件流或者生命周期,就能打破 React 对 setState 的掌控。最简单的方法,就是把 setState 放到 setTimeout 的匿名函数中。

  1. 将 setState 放在定时器中
handleClick = () => {
  setTimeout(() => {
    const fans = Math.floor(Math.random() * 10)
    console.log('开始运行')
    this.setState({
      count: this.state.count + fans
    }, () => {
      console.log('新增粉丝数:', fans)
    })
    console.log('结束运行')
  })
}

结果:

开始运行
新增粉丝数:xxx
结束运行

所以,setState 就是一次同步行为.

React 是怎么控制 setState 的

React 在绑定事件时,会对事件进行合成,统一绑定到 document 上( react@17 有所改变,变成了绑定事件到 render 时指定的那个 DOM 元素),最后由 React 来派发。

所有的事件在触发的时候,都会先调用 batchedEventUpdates$1 这个方法,在这里就会修改 executionContext 的值,React 就知道此时的 setState 在自己的掌控中。

function scheduleUpdateOnFiber(fiber, lane, eventTime) {
  if (lane === SyncLane) {
    // 同步操作
    ensureRootIsScheduled(root, eventTime);
    // 判断当前是否还在 React 事件流中
    // 如果不在,直接调用 flushSyncCallbackQueue 更新
    if (executionContext === NoContext) {
      flushSyncCallbackQueue();
    }
  } else {
    // 异步操作
  }
}

判断了 executionContext 是否等于 NoContext 来确定当前更新流程是否在 React 事件流中。

所以,不管是直接调用 flushSyncCallbackQueue ,还是推迟调用,这里本质上都是同步的,只是有个先后顺序的问题。

Component.setState 方法最终会调用 enqueueSetState 方法,而 enqueueSetState 方法内部会调用 scheduleUpdateOnFiber 方法,区别就在于正常调用的时候,scheduleUpdateOnFiber 方法内只会调用 ensureRootIsScheduled ,在事件方法结束后,才会调用 flushSyncCallbackQueue 方法。而脱离 React 事件流的时候,scheduleUpdateOnFiber 在 ensureRootIsScheduled 调用结束后,会直接调用 flushSyncCallbackQueue 方法,这个方法就是用来更新 state 并重新进行 render

结论: setState 是同步的

相关文章

  • React 中的 setState 是微任务还是宏任务

    首先这个问法就表明 setState 是一个异步的任务 和 setTimeout 以及 Promise.then ...

  • 03-19 微任务和宏任务的区别

    微任务和宏任务 微任务和宏任务是异步任务的两个种类。宏任务:当前调用栈中执行的代码成为宏任务。(主代码块,定时器等...

  • 浏览器的事件机制-Eventloop

    循环机制前,我们先要会区分:宏任务与微任务 宏任务Task与微任务Microtask JS中的宏任务和微任务的区别...

  • 宏任务/微任务 Event Loop

    宏任务/微任务 宏任务:当前调用栈中执行的任务称为宏任务。(主代码快,定时器等等)。.微任务: 当前(此次事件循环...

  • js中的宏任务、微任务

    宏任务-macroTask 包括整体代码script,setTimeout,setInterval 微任务-mic...

  • 宏任务、微任务

  • 宏任务 微任务

    宏任务 1.事件绑定 2.定时器 3.ajax/跨域中的异步(http请求异步) 微任务 1.Promise不是n...

  • 宏任务&微任务

    宏任务 我们可以将每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行) ...

  • 宏任务、微任务

    https://juejin.cn/post/6844903999506923528[https://juejin...

  • 微任务 宏任务

    微任务Microtask/Task 一次执行一个,一个执行完后检测当前(此次事件循环中)宏任务执行完,在下一个宏任...

网友评论

      本文标题:React 中的 setState 是微任务还是宏任务

      本文链接:https://www.haomeiwen.com/subject/nsixbltx.html