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

相关推荐
daols887 小时前
vxe-table 渲染器教程一:实现金额输入控件
javascript·vue.js·vxe-table
不好听6137 小时前
React vs Vue:两大前端框架技术选型深度对比
前端·vue.js·react.js
腻害兔9 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
腻害兔11 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
Larcher16 小时前
LangChain RAG 排错实录:.env 为什么没有生效
vue.js·后端
一个写前端的17 小时前
基于 Vue 3 的大文件分片上传组件,支持断点续传、并发上传、失败重试等功能
前端·javascript·vue.js
活于未来17 小时前
从零搭建期权波动率曲面可视化平台:FastAPI + Vue 3 实战
vue.js
橘子海全栈攻城狮17 小时前
【最新源码】基于SpringBoot + Vue的超市管理系统的设计与实现D002
java·开发语言·vue.js·spring boot·后端·spring
Cobyte21 小时前
使用 JavaScript 实现有限状态机的经典问题
前端·javascript·vue.js
acheding21 小时前
File System Access API 实战:让网页真正读写本地文件
前端·javascript·vue.js·编辑器·markdown