本文转载自微信公众号《FrontUpUp》,作者FrontUpUp。转载本文请联系前端UpUp公众号。setState是同步的还是异步的?首先,抛出这个问题的时候,我会想为什么会提出这个问题?如果需要依赖state的更新值,首先要怎么做呢?对于类组件,我们可以在componentDidMount或componentDidUpdate阶段执行它。对于FunctionComponent,我们可以在useEffect的回调函数中执行。首先,让我们给出一个结论。React中不同的模式有不同的情况。我们主要以两种模式为例。legacymodeconcurrentmodelegacymode这是Reactapp目前使用的方式??ReactDOM.render(,rootNode)目前没有计划移除这个模式,但是这个模式可能不支持这些新特性。回到我们上面的问题,setState是同步的还是异步的?当batchedUpdates在传统模式下命中时,setState是异步的。当遗留模式中缺少batchedUpdates时,setState是同步的。说到这里,我们来说说batchedUpdates函数的作用。那么它有什么作用呢?如果在处理逻辑函数中多次调用this.setState,它是如何更新状态的?this.setState({value:this.state.value+1})this.setState({value:this.state.value+1})this.setState({value:this.state.value+1})React实现这个批量更新操作,将多个setState组合成一个更新,那么它是如何工作的呢?batchedUpdates函数开始发挥作用。functionbatchedUpdates$1(fn,a){varprevExecutionContext=executionContext;executionContext|=BatchedContext;try{returnfn(a);}finally{executionContext=prevExecutionContext;if(executionContext===NoContext){//Flushtheimmediatecallbacksthatwerescheduledduringthisbatchreset(QuushtheimmediatecallbackscheduledsetduringRuringthis)//同步更新}}}这个函数会传一个fn。在执行fn之前,会在executionContext变量中添加一个BatchedContext。fn执行后,executionContext会去掉之前的BatchedContext标记。这样,当executionContext被BatchedContext标记时,react会在内部进行判断。有了这个标记,说明本次更新是批处理的,所以本次更新是异步的。那么,我们是否可以假设,如果我们在执行完fn函数后更新状态,是否就能完成同步更新呢?setTimeout函数,我们可以把setState放在timer里面,像这样然后执行fn函数的时候,把BatchedContext标记也去掉,然后setState的回调函数等到idle执行完,才会执行setState。setTimeout(()=>{this.setState({value:this.state.value+1})},0)这个是executionContext===NoContext的时候,也就是会执行flushSyncCallbackQueue函数来完成本次同步更新.当然,在并发模式下,就不一样了。这时候就不得不说到scheduleUpdateOnFiber这个函数了。我们都知道任务调度的起点是scheduleUpdateOnFiber方法,React.render、setState、forceUpdate、ReactHooks的dispatchAction都会经过scheduleUpdateOnFiber。functionsscheduleUpdateOnFiber(fiber,lane,eventTime){//...if(root===workInProgressRoot){//...}//TOanargumenttothatfunctionandthisone.if(lane===SyncLane){//同步任务if(//检查当前是否在unbatchedUpdates(非批量更新),(第一次渲染的ReactDOM.render是unbatchedUpdates)(executionContext&LegacyUnbatchedContext)!==NoContext&&//Checkifwe'renotalreadyrendering(executionContext&(RenderContext|CommitContext))===NoContext)//在根上注册待定交互以避免丢失跟踪交互数据。schedulePendingInteractions(root,lane);performSyncWorkOnRoot(root);}else{ensureRootIsScheduled(root,eventTime);schedulePendingInteractions(root,lane);if(executionContext===NoContext){resetRenderTimer();flushSynceback(;}}}else{//异步任务//并发模式跳过flushSyncCallbackQueue同步更新//...}}scheduleUpdateOnFiber函数使用lane===SyncLane来判断是同步任务还是异步任务,我们使用ReactDom的React应用程序.render()创建的会进入这个判断,但是在并发模式下就不一样了,那么它是怎么创建的呢??并发模式可以理解为,这个暂时还在实验阶段,等以后稳定了,会作为React开发的默认开发模式,它是如何创建ReactApp应用程序的?ReactDOM.createRoot(rootNode).render()这种模式开启了所有新特性并发模式下的状态更新是异步的。关于React的并发模式的解读,有兴趣的可以看看官方文档。至此,我们似乎对React中的setState是同步的还是异步的有了一个了解。这将命中batchUpdate机制生命周期(并调用该函数)在React中注册的事件React可以“管理条目”