(三)手写 Vue2.0 源码 —— 异步更新原理

前言

这篇是对视图更新的性能优化,包含 nextTick 这一 api 的实现,涉及到 JS 事件循环相关概念。

目前的情况是 每次改变数据都会触发相应的 watcher 进行更新,数据每变动一次就会重新渲染一次,这样很浪费性能,所以我们要让数据全部变动完毕后再去统一更新视图

一、watcher 更新的改写

  • 每次watcher进行更新的时候 是否可以让他们先缓存起来 之后再一起调用
  • 异步队列机制

src/observer/watcher.js

把 update 更新方法改了,增加异步队列的机制

二、 queueWatcher 实现队列机制

新建 scheduler.js 文件 表示和调度相关, 先同步把 watcher 都放到队列里面去 ,执行完队列的事件之后再清空队列, 主要使用 nextTick 来执行 watcher 队列。

src/observer/scheduler.js

三、nextTick 实现原理

src/util/next-tick.js

  • MutationObserver() 构造函数 主要是监听dom变化 也是一个异步方法
js 复制代码
// src/util/next-tick.js

let callbacks = [];
let pending = false;

function flushCallbacks () {
	pending = false;  // 把标志还原成 false
	for (let i = 0; i < callbacks.length; i++) {
		callbacks[i]();
	}
}

let timerFunc; // 定义异步方法,采用优雅降级
if (typeof Promise !== 'undefined') {
	// 支持 promise
	const p = Promise.resolve();
	timerFunc = () => {
		p.then(flushCallbacks);
	}
} else if (typeof MutationObserver !== 'undefined') {
	// MutationObserver 主要是监听dom变化 也是一个异步方法
	let counter = 1;
	const observer = new MutationObserver(flushCallbacks);
	const textNode = document.createTextNode(String(counter));
	observer.observe(textNode, {
		characterData: true
	})
	timerFunc = () => {
		counter = (counter + 1) % 2;
		textNode.data = String(counter);
	}
} else if (typeof setImmediate !== 'undefined') {
	// 如果前面都不支持 判断 setImmediate 
	timerFunc = () => {
		setImmediate(flushCallbacks);
	}
} else {
	// 最后降级采用 setTimeout
	timerFunc = () => {
		setTimeout(flushCallbacks, 0);
	}
}

export function nextTick (cb) {
	// 除了渲染 watcher,还有用户自己手动调用的 nextTick,一起收集到数组
	callbacks.push(cb);
	if (!pending) {
		// 如果多次调用nextTick  只会执行一次异步 等异步队列清空之后再把标志变为false
		pending = true;
		timerFunc();
	}
}

新建 util/next-tick.js 代表工具类函数 因为 nextTick 用户也可以手动调用 主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法

四、$nextTick 挂载原型

挂载在原型的nextTick方法 可供用户手动调用

src/render.js

最后把$nextTick 挂载到 Vue 的原型

最后效果

数据变化了 7 次,但是在数据变动完毕后再去更新视图

相关推荐
Dreams°1235 小时前
【Java后端+Vue前后端分离:内网正常、公网访问异常|5个高频经典踩坑完整复盘】
java·开发语言·vue.js
小蒜学长6 小时前
基于Springboot+Vue的环保行动志愿者招募系统设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
天道kabuto6 小时前
踩坑复盘:为什么在输入框按个回车,页面就偷偷刷新了?
vue.js
吴长建先生7 小时前
Vue.js支付回调页面如何设计才能保障对账准确性?
vue.js
leoZ2317 小时前
第 2 篇:搭建地基——Vue3 + Vite + Tailwind v4 + shadcn-vue
前端·javascript·vue.js·人工智能·目标检测·数据挖掘·语音识别
吴长建先生8 小时前
支付回调接口设计与代码规范:如何提升团队工程化能力
vue.js
zttbee8 小时前
vue2的API大白话讲解
前端·vue.js·前端框架
卤蛋fg611 小时前
vue 抽屉组件挂载到指定元素内显示,,表格自适应弹窗宽高
vue.js
天道kabuto1 天前
vue-i18n 升级 9.x 踩坑:正则表达式引发的“花括号”惨案
vue.js
天天喝旺仔1 天前
Vue 3 组合式 API:从 Options 迁移到 script setup
前端·javascript·vue.js