Vue3实现批量异步更新

 更新时间:2023年08月04日 09:44:44   作者:前端胖头鱼  
这篇文章主要为大家详细介绍了Vue3批量异步更新是如何实现的,文中的示例代码简洁易懂,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下

写在前面

这是Vue3源码分析的第三篇,与响应式系统中调度执行有关,其中computedwatch等核心功能都离不开它,可见其重要程度。

除了实现可调度性,我们还会借助它来实现vue中一个非常重要的功能,批量更新或者叫异步更新

多次修改数据(例如自身num10次),只进行一次页面渲染(页面只会渲染最后一次num10)。

什么是调度执行

什么是调度执行?

指的是响应式数据发生变化出发副作用函数重新执行时,我们有能力去决定副作用函数的执行时机次数方式

来看个例子

const state = reactive({
  num: 1
})
effect(() => {
  console.log('num', state.num)
})
state.num++
console.log('end')

如果我们想要它按照这个顺序书序呢?

1
end
2

你可能会说,我调换一下代码顺序就好了哇!!!

const state = reactive({
  num: 1
})
effect(() => {
  console.log('num', state.num)
})
console.log('end')
state.num++

瞬间就解决了问题。不过看起来这不是我们想要最终答案。

我们想要通过实现可调度性来解决这个问题。

如何实现可调度

我们从结果出发来思考如何实现可调度的特性。

const state = reactive({
  num: 1
})
effect(() => {
  console.log(state.num)
}, {
  // 注意这里,假如num发生变化的时候执行的是scheduler函数
  // 那么end将会被先执行,因为我们用setTimeout包裹了一层fn
  scheduler (fn) {
    // 异步执行
    setTimeout(() => {
      fn()
    }, 0)
  }
})
state.num++
console.log('end')

看到这里也许你已经明白了,我们将通过scheduler来自主控制副作用函数的执行时机。

在这之前,执行state.num++之后,console.log(state.num)将会被马上执行,而添加scheduler后,num发生变化后将执行scheduler中的逻辑。

源码实现

虽然可调度性在Vue中非常重要,但实现这个机制却非常简单,我们甚至只要增加两行代码就可以搞定。

第一行代码

// 增加options参数
const effect = function (fn, options = {}) {
  const effectFn = () => {
   // ....
  }
  // ...
  // 将options参数挂在effectFn上,便于effectFn执行时可以读取到scheduler
  effectFn.options = options
}

第二行代码

function trigger(target, key) {
// ...
  effectsToRun.forEach((effectFn) => {
    // 当指定了scheduler时,将执行scheduler而不是注册的副作用函数effectFn
    if (effectFn.options.scheduler) {
      effectFn.options.scheduler(effectFn)
    } else {
      effectFn()
    }
  })
}

是不是简单到离谱?

批量更新 & 异步更新

来看段诡异的代码,请问num会被执行多少次?100还是101?

const state = reactive({
  num: 1
})
effect(() => {
  console.log('num', state.num)
})
let count = 100
while (count--) {
  state.num++
}

对于页面渲染来说1到101中间的2~100仅仅只是过程,并不是最终的结果,处于性能考虑Vue只会渲染最后一次的101。

Vue是如何做到的呢?

利用可调度性,再加点事件循环的知识,我们就可以做到这件事。

  • num的每次变化都会导致scheduler的执行,并将注册好的副作用函数存入jobQueue队列,因为Set本身的去重性质,最终只会存在一个fn
  • 利用Promise微任务的特性,当num被更改100次之后同步代码全部执行结束后,then回调将会被执行,此时num已经是101,而jobQueue中也只有一个fn,所以最终只会打印一次101
 const state = reactive({
  num: 1
})
const jobQueue = new Set()
const p = Promise.resolve()
let isFlushing = false
const flushJob = () => {
  if (isFlushing) {
    return
  }
  isFlushing = true
  // 微任务
  p.then(() => {
    jobQueue.forEach((job) => job())
  }).finally(() => {
    // 结束后充值设置为false
    isFlushing = false
  })
}
effect(() => {
  console.log('num', state.num)
}, {
  scheduler (fn) {
    // 每次数据发生变化都往队列中添加副作用函数
    jobQueue.add(fn)
    // 并尝试刷新job,但是一个微任务只会在事件循环中执行一次,所以哪怕num变化了100次,最后也只会执行一次副作用函数
    flushJob()
  }
})
let count = 100
while (count--) {
  state.num++
}

到此这篇关于Vue3实现批量异步更新的文章就介绍到这了,更多相关Vue3异步更新内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue的el-select绑定的值无法选中el-option问题及解决

    vue的el-select绑定的值无法选中el-option问题及解决

    这篇文章主要介绍了vue的el-select绑定的值无法选中el-option问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue3实现高德地图天气小组件

    vue3实现高德地图天气小组件

    这篇文章主要为大家详细介绍了如何使用vue3实现一个高德地图天气小组件,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-10-10
  • vue3图片剪裁插件vue-img-cutter使用小结

    vue3图片剪裁插件vue-img-cutter使用小结

    Vue.js是一款流行的JavaScript前端框架,很受用户喜爱,这篇文章主要介绍了vue3图片剪裁插件vue-img-cutter使用小结,本文结合示例代码讲解的非常详细,感兴趣的朋友一起看看吧
    2024-01-01
  • vue实现移动端图片裁剪上传功能

    vue实现移动端图片裁剪上传功能

    这篇文章主要为大家详细介绍了vue实现移动端图片裁剪上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • Vue3组件渲染前的初始化过程

    Vue3组件渲染前的初始化过程

    Vue3 中一个组件从创建到挂在,会经过3个重点步骤:创建组件实例,设置组件实例,创建并执行带副作用的渲染函数,本文将着重讲清 创建组件实例、设置组件实例 这两个过程都做了什么,这部分逻辑很简单,但你会从中学习到 Vue 优秀的实践技巧,需要的朋友可以参考下
    2024-07-07
  • Vue 组件组织结构及组件注册详情

    Vue 组件组织结构及组件注册详情

    这篇文章主要介绍的是Vue 组件组织结构及组件注册,为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的,文章学详细内容,需要的朋友可以参考一下
    2021-10-10
  • vue echarts实现横向柱状图

    vue echarts实现横向柱状图

    这篇文章主要为大家详细介绍了vue echarts实现横向柱状图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • vue强制刷新组件的三种方法

    vue强制刷新组件的三种方法

    在Vue中,强制刷新组件通常涉及到以下几种方法,本文给大家列出了常见的三种vue强制刷新组件的方法,感兴趣的朋友跟随小编一起看看吧
    2024-04-04
  • vue实现登陆页面开发实践

    vue实现登陆页面开发实践

    本文主要介绍了vue实现登陆页面开发实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Vue3使用Univer Docs创建在线编辑Excel的示例代码

    Vue3使用Univer Docs创建在线编辑Excel的示例代码

    本文介绍了如何在Vue3项目中集成UniverDocs,一个基于Luckysheet的企业文档与数据协同解决方案,指导了从安装到在页面中使用的步骤,以及注意事项,如数据格式转换和二次开发的灵活性,需要的朋友可以参考下
    2025-04-04

最新评论