setState异步真的只是为了性能吗?

简介: 我们在 React 使用 setState时知道,它并不总是异步更新,也可能是同步更新,大家也知道setState使用异步是为累积更新、批量处理、减少调用次数来提升性能,但是大家有没有想过setState的异步更新真的单单是为了性能吗?

前言


我们在 React 使用 setState时知道,它并不总是异步更新,也可能是同步更新,大家也知道setState使用异步是为累积更新、批量处理、减少调用次数来提升性能,但是大家有没有想过setState的异步更新真的单单是为了性能吗?

网络异常,图片无法展示
|


setState API


setState(updater, [callback])
updater
(state, props) => stateChange


updater 函数中接收的 state 和 props 都保证为最新。updater 的返回值会与 state 进行浅合并。


callback

setState() 的第二个参数为可选的回调函数,它将在 setState 完成合并并重新渲染组件后执行。通常,我们建议使用 componentDidUpdate() 来代替此方式。


异步


setState将对组件state的更改排入队列,并通知React需要使用更新后的state重新渲染组件及其子组件。为了更好的性能,setState并不是立即进行更新,而是使用批量推迟更新。


看几个异步的例子,这些都是经常出现在面试中的代码例子(源码测试

class Test extends Component {
  state = {
    count: 0
  };
  componentDidMount() {
    this.setState({
        count: 1
      }, () => {
        console.log(this.state.count); //1
      }
    );
    console.log(this.state.count); // 0
  }
  render() {}
}
class Test extends Component {
  state = {
    count: 0
  };
  componentDidMount() {
    this.setState(
      {
        count: this.state.count + 1
      },
      () => {
        console.log(this.state.count); // 1
      }
    );
    this.setState(
      {
        count: this.state.count + 1 // 这里的count还是0,并不会拿到更新后的count
      },
      () => {
        console.log(this.state.count); // 1 
      }
    );
  }
  render() {}
}
class Test extends React.Component {
  state = {
    count: 0
  };
  componentDidMount() {
    this.setState(
      (preState) => {
        console.log(preState.count); // 0
        return {
          count: preState.count + 1
        };
      },
      () => {
        console.log(this.state.count); // 2
      }
    );
    this.setState(
      (preState) => {
        console.log(preState.count); // 1
        return {
          count: preState.count + 1
        };
      },
      () => {
        console.log(this.state.count); // 2
      }
    );
  }
  render() {
    return <div>1</div>;
  }
}码


当调用setState函数时,就会把当前的操作放入到队列中,React 根据内容合并state数据,完成之后在逐一执行回调,根据结果去更新需求DOM,触发渲染。这里采用的是异步的方法,根据说法是异步是为了累积更新,批量处理,减少渲染次数,提升性能。


难道同步就不能累积更新、批量处理了吗


这里其实我们换一个角度来想想,难道同步就不能累积更新、批量处理了吗?难道同步就不能减少渲染次数,提升性了吗?

网络异常,图片无法展示
|


这个问题其实不止我有疑问,很早之前有大佬就已经在Issues上有提出这个问题:

网络异常,图片无法展示
|


当然在这个 Issues 下面 gaearon 大佬回复了这个问题:


网络异常,图片无法展示
|

网络异常,图片无法展示
|

网络异常,图片无法展示
|


回答的比较长,大体总结了两个方面:


1. 保持一致性


如果改为同步更新的方法,虽然setState是同步的,但是props不是。


2. 为后续的架构升级启用并发更新


为了完成一部的渲染,React会在触发 setState 的时候更新数据来源分配不同的优先级。这些数据的来源有:事件回调句柄、动画效果等,在根据优先级并发处理,提升渲染性能。



目录
相关文章
|
7月前
|
编译器 数据处理 C#
C#中的异步流:使用IAsyncEnumerable<T>和await foreach实现异步数据迭代
【1月更文挑战第10天】本文介绍了C#中异步流的概念,并通过使用IAsyncEnumerable<T>接口和await foreach语句,详细阐述了如何异步地迭代数据流。异步流为处理大量数据或需要流式处理数据的场景提供了一种高效且非阻塞性的方法,使得开发者能够更优雅地处理并发和数据流问题。
|
1月前
|
前端开发 JavaScript
如何使用 Promise 处理异步并发操作?
通过使用 `Promise.all()` 和 `Promise.race()` 方法,可以灵活地处理各种异步并发操作,根据不同的业务需求选择合适的方法来提高代码的性能和效率,同时也使异步代码的逻辑更加清晰和易于维护。
|
7月前
|
JavaScript Java Spring
@Async异步失效的9种场景
在Spring中,启用@Async异步功能需要在启动类或配置类上使用`@EnableAsync`。若未使用此注解,@Async将无效。另外,内部方法调用(如在一个类的方法中调用另一个被@Async注解的方法)会导致异步功能失效,因为这不涉及Spring的AOP代理。此外,@Async方法必须是public,返回类型为void或Future,不能是static或final,且其所在的类需被@Service等注解以使Spring管理。如果使用@ComponentScan,确保正确扫描包含@Async类的包路径。
119 1
|
5月前
|
Web App开发 JavaScript 前端开发
谁说forEach不支持异步代码,只是你拿不到异步结果而已
JavaScript 的 `forEach` 不直接支持异步操作,但可以在回调中使用 `async/await`。虽然 `forEach` 不会等待 `await`,异步代码仍会执行。MDN 文档指出 `forEach` 预期同步回调。ECMAScript 规范和 V8 源码显示 `forEach` 基于 for 循环实现,不返回 Promise。通过 `setTimeout` 可观察到异步操作完成。与 `map` 不同,`forEach` 不适合处理异步序列,常需转换为 `Promise.all` 结合 `map` 的方式。
54 11
|
前端开发 JavaScript
React 中 setState 什么时候是同步的,什么时候是异步的
React 中 setState 什么时候是同步的,什么时候是异步的
146 0
|
前端开发 JavaScript
react的setState是异步还是同步
react的setState是异步还是同步
|
7月前
|
JavaScript 前端开发
揭秘 `nextTick`:解决异步回调的利器(上)
揭秘 `nextTick`:解决异步回调的利器(上)
揭秘 `nextTick`:解决异步回调的利器(上)
|
7月前
|
JavaScript 前端开发
揭秘 `nextTick`:解决异步回调的利器(下)
揭秘 `nextTick`:解决异步回调的利器(下)
揭秘 `nextTick`:解决异步回调的利器(下)
|
JavaScript 前端开发 API
深入理解Vue中的异步更新机制和$nextTick方法
在Vue开发中,我们经常会遇到需要在 DOM 更新完成后执行某些操作的情况。为了解决这个问题,Vue提供了`$nextTick`方法,它可以让我们在下次 DOM 更新完成后执行回调函数。本文将深入探讨Vue的异步更新机制、`$nextTick`的原理和使用场景,以及分别在 Vue2.x 与 Vue3.x 中的相同点和区别。
12601 48
深入理解Vue中的异步更新机制和$nextTick方法
|
前端开发
setState异步问题
setState异步问题
63 0