Vue3 的批量渲染机制的两种方法

 更新时间:2025年10月30日 11:26:44   作者:CptW  
本文主要介绍了Vue3 的批量渲染机制的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

两种机制分别指:

  1. 在 1次 回调里触发 多次 computed/effect,其只会执行 1次
  2. 在 1次 回调里 多次 更新与视图相关的 ref视图更新 也只执行 1次

举两个例子:

// effectA
effect(() => {
  console.log('A:', a.value)
  if (a.value > 5) {
    // 2、再触发第2次 effectB
    b.value = a.value * 2
  }
})

// effectB
effect(() => {
  console.log('B:', b.value)
})

// 1、更新dep, 触发1次 effectA 和 1次 effectB
a.value = 6
// 实际 effectB 只会执行 1 次,而不是 2 次
btn.onclick = () => {
  count.value++
  count.value++
  count.value++
  count.value++
}

return () => {
  console.log('render call')
  return h('div', `count: ${count.value}`)
}
// 点击按钮,实际 'render call' 只会被打印1次

如何实现的?简写源码 来说明: PS: 不熟悉响应式基础的,请移步往期文章

effect的批处理

修改响应式变量的值后,会触发 setter 里的函数 trigger,之后会沿着链表通知所有 effect

export function traggerRef(dep: RefImpl) {
  ......
    propagate(dep.subs)
  ......
}

/** 传播更新 */
export function propagate(subs: Link) {
  // 链表节点
  let link = subs
  // 收集 effect
  const queuedEffect = []
  while (link) {
    const sub = link.sub
    // 标记 dirty,防止重复触发 effect
    if (!sub.tracking && !sub.dirty) {
      sub.dirty = true
      // ......
      queuedEffect.push(sub)
      // ......
    }
    // 遍历链表
    link = link.nextSub
  }

  // 通知 effect 执行
  queuedEffect.forEach(effect => effect.notify())
}

可以看到 sub 里有一个 dirty 属性,如果同一次回调函数中,多次触发 sub,它只会被放入待执行列表 1 次,也就是不会多次执行。

注意,dirty 标志位会等 Effect 真正执行完成后才重置。

异步渲染render

mount组件的流程是:使用VNode创建组件实例instance -> 挂载到DOM -> 更新,组件实际上就是创建了一个 Effect 来订阅更新:

const mountComponent = (vnode, container, anchor) => {
    /**
     * 1、创建组件实例
     * 2、初始化状态
     * 3、挂载到DOM
     */
    // 1 实例化
    const instance = createComponentInstance(vnode)
    // 2 初始化
    setupComponent(instance)

    const componentUpdateFn = () => {
      // 首次挂载
      if (!instance.isMounted) {
        // 得到 Virtual DOM
        const subTree = instance.render()
        // 3 挂载
        patch(null, subTree, container, anchor)
        // 保存当前 V-DOM
        instance.subTree = subTree
        // 修改标志位
        instance.isMounted = true
      } else {
        // 更新
        const preSubTree = instance.subTree
        // 获取新的 V-DOM
        const subTree = instance.render()
        // 对比新旧 VNode,更新
        patch(preSubTree, subTree, container, anchor)
        instance.subTree = subTree
      }
    }

    const effect = new ReactiveEffect(componentUpdateFn)
    const update = effect.run.bind(effect)

    instance.update = update

    effect.scheduler = () => {
      queueJob(update)
    }

    effect.run()
  }

但假如有如下例子,假如点击 1次 按钮,将打印 4次 effect execute 和 1次 render call

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="app"></div>
    <button id="btn">+++</button>
    <script type="module">
      import { createApp, h, ref, effect, computed } from 'vue'

      const rootComp = {
        setup() {
          const count = ref(0)

          btn.onclick = () => {
            count.value++
            count.value++
            count.value++
            count.value++
          }

          effect(() => {
            console.log('effect execute', count.value)
          })

          return () => {
            console.log('render call')
            return h('div', `count1: ${count.value}`)
          }
        },
      }

      createApp(rootComp).mount('#app')
    </script>
  </body>
</html>

按理说 render call 也应该打印 4次,Why? 因为代码里利用 Effect.scheduler 做了 异步更新,即重写了scheduler:

const componentUpdateFn = () => {
  //......
  const update = effect.run.bind(effect)

  instance.update = update

  effect.scheduler = () => {
    queueJob(update)
  }
  //......
}

function queueJob(job) {
  Promise.resolve().then(() => {
    job()
  })
}

此时,每次 ref 更新后,不立即重置 dirty,而是等所有同步任务执行完后,再执行渲染,BINGO

到此这篇关于Vue3 的批量渲染机制的两种方法的文章就介绍到这了,更多相关Vue3 批量渲染内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue自动生成组件示例总结

    Vue自动生成组件示例总结

    在Vue中,我们可以使用unplugin-generate-component-name插件自动基于目录名称生成组件名称,这个插件使得在大型代码库中找到和管理组件更加容易和直观,这篇文章主要介绍了Vue自动生成组件示例总结,需要的朋友可以参考下
    2023-12-12
  • vue如何实现el-select下拉选项的懒加载

    vue如何实现el-select下拉选项的懒加载

    这篇文章主要介绍了vue如何实现el-select下拉选项的懒加载,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • vue3如何利用自定义指令实现下拉框分页懒加载

    vue3如何利用自定义指令实现下拉框分页懒加载

    下拉框一开始请求第一页的内容,滚动到最后的时候,请求第二页的内容,如此反复,直到所有数据加载完成,这篇文章主要介绍了vue3如何利用自定义指令实现下拉框分页懒加载,需要的朋友可以参考下
    2024-07-07
  • element表格数据部分模糊的实现代码

    element表格数据部分模糊的实现代码

    这篇文章给大家介绍了element表格数据模糊的实现代码,文中有详细的效果展示和实现代码供大家参考,具有一定的参考价值,需要的朋友可以参考下
    2024-01-01
  • 关于vue2使用element UI中Descriptions组件的遍历问题详解

    关于vue2使用element UI中Descriptions组件的遍历问题详解

    最近element-ui遇到了很多坑,下面这篇文章主要给大家介绍了关于vue2使用element UI中Descriptions组件的遍历问题,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • vue通过过滤器实现数据格式化

    vue通过过滤器实现数据格式化

    这篇文章主要介绍了vue通过过滤器实现数据格式化的方法,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • Vue3.0 axios跨域请求代理服务器配置方式

    Vue3.0 axios跨域请求代理服务器配置方式

    这篇文章主要介绍了Vue3.0 axios跨域请求代理服务器配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Vue3.2 中新出的Expose用法一览

    Vue3.2 中新出的Expose用法一览

    这篇文章主要介绍了Vue3.2 中新出的 Expose 是做啥用的,新的expose方法是非常直观的,而且很容易在我们的组件中实现,本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • vue 地图可视化 maptalks 篇实例代码详解

    vue 地图可视化 maptalks 篇实例代码详解

    这篇文章主要介绍了vue 地图可视化 maptalks 篇,本文分步骤通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-05-05
  • IDEA中Debug调试VUE前端项目调试JS只需两步

    IDEA中Debug调试VUE前端项目调试JS只需两步

    这篇文章主要为大家介绍了在IDEA中Debug调试VUE前端项目,只需要两步就可以调试JS的实现方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-02-02

最新评论