• Vue源码学习(十二):列队处理(防抖优化,多次调用,只处理一次)


    好家伙,

     

    本篇讲的是数据更新请求列队处理

     

    1.一些性能问题

    数据更新的核心方法是watcher.updata方法

    实际上也就是vm._updata()方法,

    vm._updata()方法中的patch()方法用于将新的虚拟DOM树与旧的虚拟DOM树进行比较,

    并将差异更新到实际的DOM树上.

    这一步是非常消耗性能的

     

    2."问题"实例

    来写一个多次更新的例子

     这里我们可以看到,updata被触发了三次,也就是 .patch()方法被触发了三次

    同样的操作做了三次,显然后两次是多余的

    这显然是可以优化的,我们来做些优化吧

     

    3.优化

    先讲一下思路组件与watcher一一对应

    1.当三个请求同时发出,我们只进行一次操作

    2.将需要操作的watcher存到一个数组中,在单次操作中调用更新方法

    有点抽象

    上代码:

    复制代码
    class Watcher{
        /* 
        xxx
        */
        run(){
            this.getter()
        }
        updata() { //三次
            //注意:不要数据更新后每次都调用 get 方法 ,get 方法回重新渲染
            //缓存
            // this.get() //重新渲染
            queueWatcher(this)
        }
    
    }
    let queue = [] // 将需要批量更新的watcher 存放到一个列队中
    let has = {}
    let pending = false
    
    function queueWatcher(watcher) {
        let id = watcher.id // 每个组件都是同一个 watcher
           console.log(id) //去重
        if (has[id] == null) {//去重
            //列队处理
            queue.push(watcher)//将wacher 添加到列队中
            has[id] = true
            //防抖 :用户触发多次,只触发一个 异步,同步
            if (!pending) {
                // 异步:等待同步代码执行完毕之后,再执行
                setTimeout(()=>{
                  queue.forEach(item=>item.run())
                  queue = []
                  has = {}
                  pending = false
                },0)
            }
            pending = true
        }
    }
    复制代码

    此处,

     

    a. 首先获取到 watcher 的 id(假设每个组件都是同一个 watcher)。

    b. 判断队列中是否已存在相同的 watcher,通过判断 has 对象中是否存在该 id 来实现。

    c. 如果队列中不存在该 watcher,将其添加到队列中,并将该 id 添加到 has 对象中,表示已存在。

    d. 通过 setTimeout 将队列中的所有 watcher 的 run 方法封装成一个异步任务,等待当前同步代码执行完毕后执行

    e. 设置 pending 为 true,表示当前有一个异步任务正在执行。

    f.  执行setTimeout()中的代码

     

    这样第一次执行了if()块,随后的几次操作中pending被设置为true后if()块不再执行

    同步任务完成后,执行异步任务

     

    这样,通过异步处理的方式实现了,触发多次,只执行一次的效果

     

  • 相关阅读:
    EMQX 企业版正式上架华为云 OSC,助力企业实现云原生MQTT消息服务器的全生命周期管理
    对象可达性状态流转分析、显式地影响软引用垃圾收集
    Java NIO的Buffer缓冲区和Channel通道详细总结
    AP5101C 高压线性恒流 LED电源驱动IC 3D打印机显示灯驱动器
    单元测试是什么?怎么写?主要测试什么?
    Qt通过QMetaObject创建实例
    颜色遍历法非递归遍历二叉树
    C#演示抽象工厂模式
    手把手教你使用 Spring Boot 3 开发上线一个前后端分离的生产级系统(九) - Spring AMQP 集成与配置
    Unity 如何把UGUI做到极致的优化
  • 原文地址:https://www.cnblogs.com/FatTiger4399/p/17775316.html