本文转载自微信公众号「前端UpUp」,作者前端UpUp。转载本文请联系前端UpUp公众号。
setState是同步还是异步?
首先,这个问题的抛出,我会想为什么要抛出这个问题呢?如果说,你需要依赖状态更新后的值时,那么首先如何做呢?
首先,我们先给出结论,在React中不同的模式它的情况是不一样的,主要拿两种模式来说。
legacy 模式
这是当前 React app 使用的方式??
- ReactDOM.render(<App />, rootNode)
当前没有计划删除本模式,但是这个模式可能不支持这些新功能。
回到我们上述的问题,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函数就登场了。
- function batchedUpdates$1(fn, a) {
- var prevExecutionContext = executionContext;
- executionContext |= BatchedContext;
- try {
- return fn(a);
- } finally {
- executionContext = prevExecutionContext;
- if (executionContext === NoContext) {
- // Flush the immediate callbacks that were scheduled during this batch
- resetRenderTimer();
- flushSyncCallbackQueue(); // 同步的更新
- }
- }
- }
这个函数会传递一个fn,当执行fn之前,会在executionContext变量上附加一个BatchedContext,当fn执行完毕后,executionContext就会把之前的BatchedContext标记给去除掉。
那么,我们是不是能够假设一下,如果在执行完fn函数后,再去更新状态的话,是不是就能完成同步的更新呢?
setTimeout函数,我们可以把setState放在定时器中,这样子一来的话,当fn函数执行完时,BatchedContext标记也去掉了,然后等到 setTimeout 的回调函数等到空闲被执行的时候,才会执行 setState。
- setTimeout(() => {
- this.setState({ value: this.state.value + 1})
- }, 0)
这也就是当executionContext === NoContext,也就是会执行flushSyncCallbackQueue函数,完成此次的同步更新。
当然了,在concurrent 模式下,又是有所不同的。
这个时候,我们得谈一谈scheduleUpdateOnFiber函数。
我们都知道任务调度的起点是 scheduleUpdateOnFiber 方法,React.render、setState、forceUpdate、React Hooks 的dispatchAction 都会经过 scheduleUpdateOnFiber。
- function scheduleUpdateOnFiber(fiber, lane, eventTime) {
- // ...
- if (root === workInProgressRoot) {
- // ......
- } // TO an argument to that function and this one.
- if (lane === SyncLane) { // 同步任务
- if ( // 检查当前是不是在unbatchedUpdates(非批量更新),(初次渲染的ReactDOM.render就是unbatchedUpdates)
- (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering
- (executionContext & (RenderContext | CommitContext)) === NoContext) {
- // Register pending interactions on the root to avoid losing traced interaction data.
- schedulePendingInteractions(root, lane);
- performSyncWorkOnRoot(root);
- } else {
- ensureRootIsScheduled(root, eventTime);
- schedulePendingInteractions(root, lane);
- if (executionContext === NoContext) {
- resetRenderTimer();
- flushSyncCallbackQueue();
- }
- }
- } else { // 异步任务
- // concurrent模式下是跳过了 flushSyncCallbackQueue 同步更新
- // ....
- }
- }
scheduleUpdateOnFiber函数通过lane === SyncLane来判断是同步任务还是异步任务,我们通过ReactDom.render()方式创建的React app是会进入这个判断的,而concurrent模式下,则不同,那么它是如何创建的呢??
concurrent 模式
你可以理解成,这个暂时还是实验阶段,当未来稳定后,将会作为React开发的默认开发模式,它是如何创建一个React App应用的呢??
- ReactDOM.createRoot(rootNode).render(<App />)
这个模式开启了所有的新功能。
concurrent模式下状态的更新都是异步的。
关于React的concurrent 模式解读,有兴趣可以看看官方文档。
到这里的话,似乎我们对React中setState是同步的还是异步的就有所了解了。
怎么升级 虚拟主机 ?当网站运营到一定阶段,虚拟主机配置跟不上网站发展,这时...
本文转载自微信公众号「脑子进煎鱼了」,作者陈煎鱼 。转载本文请联系脑子进煎鱼...
作者 | 黄玉奇 来源 | 阿里巴巴云原生公众号 日前,在由全球分布式云联盟主办的...
随着云计算、物联网、移动互联网等互联网技术的快速发展,人们对于网络技术的依...
2020年,AWS的年收入规模已经超过450亿美元,营收增速和运营利润率超过30%。IDC...
hk 域名 哪里注册? .hk域名 在国内是可以注册的,只要提供了.hk 域名注册 服务...
FFmpeg备忘清单 ffmpeg命令行工具的有用命令列表。 下载FFmpeg:https://www.ffm...
只有 域名 能备案吗?不能的,备案是需要国内空间的, 虚拟主机 或者服务器的都...
深入浅出AbstractQueuedSynchronizer 在Java多线程编程中,重入锁(ReentrantLock...
对于广大的 Flink 开发者同学来说, 什么内容是最期待的? 什么信息又是最有用的...