相关文章推荐
爱跑步的香蕉  ·  react17+18 中 ...·  1 月前    · 
飘逸的黄瓜  ·  MotionEvent Class ...·  8 月前    · 
俊逸的铅笔  ·  页面未找到 - 七牛云·  1 年前    · 

React setState有同步有异步,那么同情况下的Vue呢?

首先:关于 React useState和setState到底是同步还是异步?

可以看这位朋友写的: juejin.cn/post/695988…

总结一下(React useState和setState到底是同步还是异步?)

  • 通过react事件流控制的(比如onClick)或生命周期或hook(总之是 react api控制的 ),就是 异步
  • setState和useState都是异步执行的(不会立即更新state的结果)
  • 多次执行setState和useState,只会调用一次重新渲染render
  • 不同的是,setState会进行state的合并,而useState则不会
  • 通过 js原生api ,比如setTimeout,promise,addEventListener等。都 超出了react的控制范围 的,就是 同步 执行的( 有几个setState就render几次
  • setState和useState是同步执行的(立即更新state的结果)
  • 多次执行setState和useState,每一次的执行setState和useState,都会调用一次render
  • 此例子能说明(注意看注释) react在原生js api内执行多个setState 有性能问题

  • 放在 promise和addEventListener内的 setState 是 同步 的, 会render N次 (性能更不好,重复render了)
  • class Component extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          a: 1,
      componentDidMount() {
        document.addEventListener('click', () => { // 非按钮处,点击一下
          this.handleClickWithoutPromise() // 两次 setState 各自 render 一次,分别打印 2,3
      handleClickWithPromise = () => {
        Promise.resolve().then(() => {
          this.setState({a: this.state.a + 1})
          this.setState({a: this.state.a + 1})
          console.log(this.state.a) // 同步执行 拿最终结果 3
      handleClickWithoutPromise = () => {
        this.setState({a: this.state.a + 1})
        this.setState({a: this.state.a + 1})
        console.log(this.state.a) // 异步执行 拿初始值 1 
      render() {
        // 当点击同步执行按钮时,两次 setState 合并,只执行了最后一次,此处log 打印 2
        // 当点击异步执行按钮时,两次 setState 各自 render 一次,此处log分别 打印 2,3
        console.log('a', this.state.a)
        return (
              {this.state.a}
              <button onClick={this.handleClickWithPromise}>放在promise内, 结果是同步执行setState, 会render N次, 损害性能</button>
              <button onClick={this.handleClickWithoutPromise}>受react控制, 异步执行, 会合并setState, 只会render 1次, 性能更好</button>
    

    相同的demo,在vue中是什么情况呢?

    先说结论:

    对于vue来说,并没有这种性能问题,vue不受js原生api的影响

  • 因为vue是对数据的变化做劫持无论是否是原生js api操作数据,数据都可以被劫持到
  • 数据劫持的api的使用(源码自带):vue2是es5的Object.definedProperty。vue3是es6的new Proxy()
  • vue会把一次同步任务内的操作,都合并起来,只render一次。 不受setTimeout,promise,addEventListener等api的影响
  • 以下demo配置:vue3 + jsx 写法 (vue3和vue2都是对数据做劫持)

  • 注意看注释,和按钮的名字
  • import { defineComponent, ref } from 'vue'
    export default defineComponent({
      setup () {
        const a = ref(1) // 不熟悉vue的,可以把这个理解为 react的 const [a, setA] = useState(1)
        console.log(a.value) // 打印a的值
        return () => {
          console.log(a.value) // 此处可以测试,vue的render的次数
          return (
            <div class="projectList">
              <div>{a.value}</div>
              <button onClick={() => {
                a.value = a.value + 1
                a.value = a.value + 1
                console.log(a.value) // 正常打印3,只触发一次render
              }}>普通按钮,正常打印,只触发一次render</button>
              <button onClick={() => {
                setTimeout(() => {
                  a.value = a.value + 1
                  a.value = a.value + 1
                  console.log(a.value) // 正常打印3,只触发一次render
              }}>不受setTimeout影响,正常打印,只触发一次render</button>
              <button onClick={() => {
                setTimeout(() => { // 第一个异步任务
                  a.value = a.value + 1
                  a.value = a.value + 1
                  console.log(a.value) // 正常打印3,触发第一次render
                  setTimeout(() => { // 第二个异步任务
                    a.value = a.value + 1
                    a.value = a.value + 1
                    console.log(a.value) // 正常打印5,触发第二次render
              }}>两层setTimeout按钮,只受异步任务的影响,正常打印,只触发两次render</button>
            </div>
    

    react的多个setState并发执行 区分同步和异步

  • 正常如果受react api(react事件流、生命周期钩子、hook)控制的话,就是异步的(提高性能,只会render一次
  • 如果不受react控制(比如js原生api:setTimeout,promise,addEventListener等),就会同步执行,render N次,性能更不好
  • 对于vue来说,并没有这种性能问题,vue不受js原生api的影响

  • 因为vue是对数据的变化做劫持无论是否是原生js api操作数据,数据都可以被劫持到
  • vue会把一次同步任务内的操作,都合并起来,只render一次。  不受setTimeout,promise,addEventListener等api的影响 多个数据并发被修改的情况,vue是同步还是异步?
  • 数据的变更是同步的。但是render是异步的
  • 可以理解为:一次同步任务内,无论怎么同步执行修改数据,都不会render,最终的render会在同步任务结束后的 异步微任务中去执行
  • vue的源码内,就是用Promise.resolve().then( 在这里面执行render )
  • 微任务的优先级比setTimeout要高,所以两层setTimeout会执行2次render
  • 谢谢思考!

    码字不易,点赞鼓励!

  • 在 React Router 中使用 JWT
  • 基于 ChatGPT 和 React 搭建 JSON 转 TS 的 Web 应用
  • ChatGPT保姆级教程,一分钟学会使用ChatGPT!
  • 2022 年的 React 生态
  • 私信