【vue设计与实现】响应系统的作用与实现 7-立即执行的watch与回调执行时机

从上一节可以看到,watch的本质其实是对effect的二次封装。这里继续讨论watch的两个特性:一个是立即执行的回调函数,另一个是回调函数的执行时机。
首先来看立即执行的回调函数。默认情况下,一个watch的回调只会在响应式数据发生变化时才执行。

在Vue.js中可以通过选项参数immediate来指定回调是否需要立即执行:

watch(obj,()=>{
	console.log('变化了')
},{
	// 回调函数会在watch创建时立即执行一次
	immediate:true
})

其实回调函数的立即执行与后续执行本质上没有任何差别,要做的就是把scheduler调度函数封装为一个通用函数,分别在初始化和变更时执行,如下面代码:

function watch(source, cb, options = {}){
	let getter
	if(typeof source === 'function'){
		getter = source
	}else{
		getter = () => traverse(source)
	}
	
	let oldValue, newValue
	// 提取scheduler调度函数为一个独立的job函数
	const job = () => {
		newValue = effectFn()
		cb(newValue, oldValue)
		oldValue = newValue
	}
	
	const effectFn = effect(
		// 执行getter
		() => getter(),
		{
			lazy: true
			// 使用job函数作为调度器函数
			scheduler: job
		}
	)

	if(options.immediate){
		// 当immediate为true时立即执行job,从而触发回调执行
		job()
	}else{
		oldValue = effectFn()
	}
}

由于回调函数时立即执行的,所以第一次回调执行时没有所谓的旧值,因此回调函数此时的oldValue值为undefined

还可以通过其他选项参数来指定回调函数的执行时机,例如在Vue.js 3中使用flush选项来指定:

watch(obj, ()=>{
	console.log('变化了')
}{
	// 回调函数会在watch创建是立即执行一次
	flush: 'pre' // 还可以指定为 'post' | 'sync'		
})

flush本质上市在指定调度函数的执行时机。flush的功能与scheduler相同,当flush的值为’post’时,代表调度函数需要将副作用函数放到一个微任务队列中,并等待DOM更新结束后再执行,可以用如下代码进行模拟:

function watch(source, cb, options = {}){
	let getter
	if(typeof source === 'function'){
		getter = source
	}else{
		getter = () => traverse(source)
	}

	let oldValue, newValue
	// 提取scheduler调度函数为一个独立的job函数
	const job = () => {
		newValue = effectFn()
		cb(newValue, oldValue)
		oldValue = newValue
	}
	
	const effectFn = effect(
		// 执行getter
		() => getter(),
		{
			lazy: true,
			scheduler: () => {
				// 在调度函数中判断flush是否为‘post’,如果是,将其放到微任务队列中执行
				if(options.flush === 'post'){
					const p = Promise.resolve()
					p.then(job)
				}else{
					job()
				}
			}
		}
	)

	if(options.immediate){
		job()
	}else{
		oldValue = effectFn()
	}
}

如上当options.flush的值为post时,将job函数放到微任务队列中,从而实现异步延迟执行;否则直接执行job函数,本质上相当于‘sync’的实现机制,即同步执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值