(三)手写 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 次,但是在数据变动完毕后再去更新视图

相关推荐
li357418 小时前
将已有 Vue 项目通过 Electron 打包为桌面客户端的完整步骤
前端·vue.js·electron
Icoolkj19 小时前
VuePress 与 VitePress 深度对比:特性、差异与选型指南
前端·javascript·vue.js
萌萌哒草头将军1 天前
10个 ES2025 新特性速览!🚀🚀🚀
前端·javascript·vue.js
Zz_waiting.1 天前
Javaweb 14.4 Vue3 视图渲染技术
前端·javascript·vue.js
前端开发爱好者1 天前
一键 i18n 国际化神库!适配 Vue、React!
前端·javascript·vue.js
前端开发爱好者1 天前
Vite 移动端调试利器!开发效率飙升 300%!
前端·javascript·vue.js
weixin_456904271 天前
Vscode中开发VUE项目的调试方案
ide·vue.js·vscode
BillKu1 天前
容器元素的滚动条回到顶部
前端·javascript·vue.js
鱼钓猫1 天前
H5 电子签名组件
vue.js·canvas
就是帅我不改1 天前
敏感词过滤黑科技!SpringBoot+Vue3+TS强强联手,打造无懈可击的内容安全防线
前端·vue.js·后端