likes
comments
collection
share

如何理解Vue的批处理和react有什么区别?

作者站长头像
站长
· 阅读数 21

先有问题再有答案

  1. 如何理解Vue的批处理?
  2. 与浏览器的event loop有什么关系 ?
  3. vue自动收集 批量更新的基本单位是什么?
  4. 和react批处理有什么区别嘛?

前置文章

如何理解vue的批处理

case1

<script setup>
const count = ref(0);
let render = 0;

onUpdated(() => {
  console.log("update render:", render++);
});

const onBtn1 = () => {
  for (let i = 0; i < 5; i++) {
    count.value++;
  }
};
</script>

在这段代码中,for循环五次增加count的值,但是并不会触发五次组件的重新渲染。在Vue.js的响应式系统中,如果在同一个事件循环(event loop)内多次改变一个响应式变量的值,那么Vue.js会在这个事件循环结束后,用一个微任务(microtask)去触发这个响应式变量的依赖更新,然后进行组件的重新渲染。

因此,尽管count.value在onBtn1函数中改变了五次,但是它们都在同一个事件循环内,所以Vue.js会在这个事件循环结束后,只触发一次更新,并且只会重新渲染一次组件。所以,console.log("update render:", render++);只会打印一次最终值。

如何理解Vue的批处理和react有什么区别?

case2

<script setup>
const count = ref(0);
let render = 0;

onUpdated(() => {
  console.log("update render:", render++);
});

const onBtn2 = () => {
  for (let i = 0; i < 5; i++) {
    setTimeout(() => {
      count.value++;
    }, 1000);
  }
};
</script>

在 onBtn2 函数中,count.value 的增加操作被放在了一个 setTimeout 函数里,设置了 1000ms 的延迟。同时,这个操作执行了 5 次。

由于 setTimeout 函数会让count.value++ 分别在5个不同的宏任务(macrotask)队列中执行,事件循环会处理完JavaScript主线程上的任务,然后再处理宏任务队列中的下一个任务。在这里,这将分别在大约1秒的时间间隔内递增5次 count.value。

因此,这段代码里的 console.log("update render:", render++); 将会被打印五次,因为每次 setTimeout 中的回调函数被执行时,count.value 的改变,会触发组件的重新渲染,从而触发 onUpdated。而多次count.value++操作都处于不同的宏任务队列中,所以组件将会有 5 次独立的更新和重新渲染操作。

如何理解Vue的批处理和react有什么区别?

case 3

const count = ref(0);
let render = 0;

onUpdated(() => {
  console.log("update render:", render++);
});

const onBtn3 = () => {
  setTimeout(() => {
    for (let i = 0; i < 5; i++) {
      count.value++;
    }
  }, 1000);
};

在 onBtn3 函数中,count.value 的增加操作被放在了一个 setTimeout 函数里,设置了 1000ms的延迟,并在这个 setTimeout 函数内通过 for 循环进行了五次递增操作。

setTimeout 函数会将回调函数放入 Event Loop 的宏任务队列,会等到 JavaScript 主线程上的代码执行完毕后,再去执行这个队列中的任务。

在一个单独的 setTimeout 任务中,尽管 count.value 被改变了五次,但这五次改变都发生在同一个宏任务队列中。根据 Vue 的异步更新策略,这些改变将被合并,只会触发一次组件的更新。因此,这段代码里的 console.log("update render:", render++); 将会只被打印一次。

如何理解Vue的批处理和react有什么区别?

vue & event-loop总结

如何理解Vue的批处理和react有什么区别?

react中的批处理

如何理解Vue的批处理和react有什么区别?

在 React 的同步生命周期方法或事件处理器中,多次连续的状态更新通常会被合并,所以只会引起一次重新渲染。这种行为称为状态更新的批处理(batching)。批处理提高了性能,因为它减少了不必要的重新渲染次数。

在某些情况下,这种批处理机制可能不会按预期工作,导致状态更新被单独处理,从而引起多次渲染。以下是一些批处理可能“失效”或不被应用的情况: 异步操作:只有同步代码中的状态更新会自动被批处理。在异步操作中(如 setTimeout、Promise、异步事件处理等)触发的状态更新不会被自动批处理,每个状态更新都可能引起一次单独的重新渲染。 非 React 事件处理器:由非 React 的事件管理(如直接添加到 DOM 元素上的事件监听器)触发的状态更新,不会被自动批处理,因为 React 无法捕获和控制这些更新。

react&vue 批处理差异

主要的差异在于两者的合并契机不同 vue是以event-loop为单位的自动合并。react是以内部的生命周期方法或事件处理器为单元的手动合并。

const count = ref(0);
let render = 0;

onUpdated(() => {
  console.log("update render:", render++);
});

const onBtn3 = () => {
  setTimeout(() => {
    for (let i = 0; i < 5; i++) {
      count.value++;
    }
  }, 1000);
};

这段代码vue只会更新一次。 如果换为react的版本(v16)

    const [count, setCount] = useState(-1);

    useEffect(() => {
        console.log('test update', count);
    }, [count]);

    const onBtn3 = () => {
        setTimeout(() => {
            for (let i = 0; i < 5; i++) {
                setCount(i);
            }
        }, 1000);
    };

如何理解Vue的批处理和react有什么区别?

setTimeout虽然是在同一个时间循环内,但是因为不在react生命周期和合成事件中 所以每次调用setCount都会触发更新。

当然这个批处理的合并机制 在react 18中已经有所变更. 在react生命周期外也可以做到任务合并。

转载自:https://juejin.cn/post/7394366490395574307
评论
请登录