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

相关推荐
多看书少吃饭1 小时前
从Vue到Nuxt.js
前端·javascript·vue.js
前端不太难2 小时前
《Vue 项目路由 + Layout 的最佳实践》
前端·javascript·vue.js
老华带你飞2 小时前
物流信息管理|基于springboot 物流信息管理系统(源码+数据库+文档)
数据库·vue.js·spring boot
想学后端的前端工程师3 小时前
【Vue3组合式API实战指南:告别Options API的烦恼】
前端·javascript·vue.js
毕设源码-邱学长4 小时前
【开题答辩全过程】以 基于VUE的藏品管理系统的设计与实现为例,包含答辩的问题和答案
前端·javascript·vue.js
学习CS的小白6 小时前
跨域问题详解
vue.js·后端
周星星日记6 小时前
5.为什么vue中使用query可以保留参数
前端·vue.js
+VX:Fegn08956 小时前
计算机毕业设计|基于springboot + vue作业管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
Tzarevich6 小时前
现代前端开发工程化:从 Vite 到 Vue 3 多页面应用实战
vue.js·vite
JIngJaneIL8 小时前
基于java+ vue办公管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端