深入Vue源码分析-异步更新队列(nextTick)源码分析

目录

异步更新原理

异步更新队列(对模板渲染的性能优化)

nextTick


异步渲染队列

 

异步更新原理

异步更新队列(对模板渲染的性能优化)

当模板中存在多处变量依赖的时候,每一个变量修改的时候,都会导致一次渲染,是否可以优化?

let active; // 表明当前是一个正在执行的函数

let watch = function(cb) { // 接收一个回调函数参数
    active = cb;
    active();
    active = null; // 保证active只会添加一次,用完销毁掉
}

let queue = []; // 声明对列
let nextTick = (cb) => Promise.resolve().then(cb); // 将队列放置入微任务队列
    
let queueJob = job => {
    if(!queue.includes(job)){// 如果queue队列里没有job
      // 就把他加进去
      queue.push(job);
      nextTick(flushJobs); 
    }
}

let flushJobs = () => {
    let job;
    while((job = queue.shift()) !== undefined) { 
    	// shift() 方法移除数组的第一项。
    	// shift() 方法会改变数组的长度。
    	// shift 方法的返回值是被移除的项目。
    	// shift() 方法会改变原始数组。
     	// 如需删除数组的最后一项,请使用 pop() 方法。
    	// 执行任务
        job();    
    }
}

// 假如说有很多 要监听的数据,和它的回调执行,就要有一个依赖收集类
class Dep { // 依赖收集类
    deps = new Set();
    depend() { // 进行一次依赖收集,相应的依赖加到deps里面
        if(active){ // active非空的
            this.deps.add(active);        
        }    
    }
    notify() { // 对当前有的deps方法,进行一次执行
    	this.deps.forEach(dep => queueJob(dep)) // 添加队列
    }
}

let ref = initValue => { 
    // 闭包2个对象,一个是value,一个是依赖Dep
    let value = initValue; // 闭包一个value,初始值是initValue
    let dep = new Dep(); // 初始化Dep
    // 新对象,里面包含了一个value属性,这个属性里面包括了get,set函数
    return Object.defineProperty({}, "value",{ // 代理
        get() {
            dep.depend(); // 添加依赖
            return value;        
        },
        set(newValue) {
            value = newValue; 
            // active();  执行
            dep.notify() 
        }
    })
}
// 因为我们要使用Object.defineProperty,把x修改成引用类型的值 
// x使用ref(1)时,就创建了个新的对象【ref(1),得到了一个代理的对象】
let x = ref(1); // 
let y = ref(2); // 
let z = ref(3); // 
let str;
watch(() => {
  str = `hello${x.value}- ${y.value} -${z.value}`
  console.log(1,str);
    document.write(`${str}<br/>`);
})

x.value = 2; 
y.value = 2;
z.value = 2;
x.value = 3;
nextTick(() => {
    console.log(x.value);
    console.log(2, str);
    console.log(x.value);
})

nextTick

在下次DOM更新循环结束之后执行延迟回调(把dom渲染队列【通过Promise】放入了微任务队列)

Vue.nextTick([callback, context]) // 全局的渲染,this为context
vm.$nextTick([callback]) // 实例vm上的,this会绑定在vm实例上
// 它们都会将回调延迟到下次DOM更新循环后执行。
// 通常用于在修改数据之后使用这个方法,在回调中获取更新后的DOM。
mounted: function() { // 视图渲染完毕
    this.$nextTick(function() {
        // 这里代码将在当前组件和所有子组件挂载完毕之后执行    
    })
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值