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

剖析setState源码,揭秘到底是同步OR异步 #2

Open
hexiaokang opened this issue Aug 25, 2022 · 0 comments
Open

剖析setState源码,揭秘到底是同步OR异步 #2

hexiaokang opened this issue Aug 25, 2022 · 0 comments

Comments

@hexiaokang
Copy link
Owner

hexiaokang commented Aug 25, 2022

问题:setState()到底是同步还是异步?

请看如下场景:

image

结论:

  • 在 >= v18.0.0 时,任何位置调用setState都是异步更新的
  • 在 < v18.0.0 时,视调用位置的不同分两种情况:
    1、所有在React自身的调度流程中调用时都是异步的,比如生命周期(componentDidMount\componentDidUpdate...)、合成事件(onClick\onMouseEnter...)等
    2、在JS原生事件、异步事件、DOM元素绑定的原生事件等都是同步更新的(比如:setTimeout、setInterval、async\await等等)

源码分析

首先,我们来看低于V18.0.0版本以下的。
1、调用setState()后会依次经历以下函数过程:
setState > enqueueSetState > scheduleUpdateOnFiber > flushSyncCallbackQueue
2、flushSyncCallbackQueue是具体执行同步更新的函数,控制是否调用同步的逻辑在scheduleUpdateOnFiber中,所以我们来重点看下scheduleUpdateOnFiber内部的逻辑

image

从上图圈出的重点内容可以看出,控制是否同步更新的是executionContext变量,那么executionContext变量是什么?何时为NoContent?
executionContext是一个全局变量,标识当前React 执行的阶段。当executionContext值为NoContent时,setState即会同步更新state。那么executionContext何时会修改值?搜索全局发现,进入任何一个React自身的调度事件中都会被赋予相应不同的状态。如下几种式例:

image

image

executionContext默认值为NoContent, 所以 ,在React自身调度流程中执行setState是异步更新,其他未进入的则是同步更新。

接下来我们看V18的scheduleUpdateOnFiber函数:

image

从圈中部分可以看出,要执行同步更新时新增了条件判断,其中一个条件是必须在非concurrent模式下才可进入,react版本不同采用的模式也不同,主要有Legacy、blocking、Concurrent模式。而V18版本以后已经全面采用Concurrent模式,因为功能最全面。所以V18版本以后调用setState都是异步的。 - 但需要理解,setState的异步行为并不是代表setState内代码执行是异步的,其实内部代码是同步的,只不过生命周期和合成事件的执行顺序都在更新之前,所以没法立即拿到修改后的state,需要更新后才能拿到,所以才导致异步效果。目的是为了“批量优化”!

useState中使用setState时有何区别

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