V1.6.1性能优化:高频路径提速与代码精简

v1.6.1 针对 isSameQuery 和 Object.freeze 两处高频执行路径进行优化,减少不必要的计算开销与重复代码

前言

v1.6.0 引入了 params 页面参数传递和查询参数增强方法,功能更加完整。但在实际使用中,路由状态管理存在两处可优化的细节:

  1. isSameQuery 缺少空对象快速路径 --- 每次导航、守卫执行、状态同步都会调用 isSameQuery,而空对象是常见场景
  2. Object.freeze 逻辑分散 --- meta、query、params 的冻结逻辑分散在 setCurrentRoute 和 createStartLocation 中,存在重复代码

v1.6.1 针对这两处进行优化,在不改变任何外部行为的前提下提升性能和可维护性。


一、isSameQuery 空对象快速路径

问题分析

isSameQuery 在路由器内部被高频调用:

  • setCurrentRoute 中判断 from 和 to 是否相同
  • syncCurrentRoute 中比较当前查询参数
  • isSameRouteLocation 中作为路由位置比较的一部分

原始实现无论查询参数是否为空对象,都会执行 Object.keys() 和 every() 遍历:

typescript 复制代码
// 优化前
private isSameQuery(a: Record<string, string>, b: Record<string, string>): boolean {
    const keysA = Object.keys(a)
    const keysB = Object.keys(b)
    if (keysA.length !== keysB.length) return false
    return keysA.every(key => a[key] === b[key])
}

在空对象场景下(如首页导航、无参数跳转),Object.keys({}) 返回空数组,every 对空数组返回 true,虽然结果正确,但产生了不必要的函数调用开销。

优化方案

添加两层快速路径:

typescript 复制代码
// 优化后
private isSameQuery(a: Record<string, string>, b: Record<string, string>): boolean {
    if (a === b) return true              // 快速路径 1:引用相等
    const keysA = Object.keys(a)
    const keysB = Object.keys(b)
    if (keysA.length !== keysB.length) return false
    if (keysA.length === 0) return true   // 快速路径 2:双空对象
    return keysA.every(key => a[key] === b[key])
}

快速路径 1:引用相等(a === b)

当 a 和 b 是同一个对象引用时,直接返回 true。这种情况在路由状态未变化时(如重复导航检测)经常出现。

快速路径 2:双空对象(keysA.length === 0)

当 keysA.length === keysB.length 且 keysA.length === 0 时,说明两者都是空对象,直接返回 true。避免了 every 对空数组的调用。

性能影响

场景 优化前 优化后
引用相等 Object.keys + every 直接返回 true
双空对象 Object.keys × 2 + every Object.keys × 2 + 长度判断
非空对象 不受影响 不受影响

对于高频调用的导航场景(特别是无参数跳转),减少了不必要的 Object.keys 和 every 开销。


二、Object.freeze 逻辑集中化

问题分析

v1.6.0 中,meta、query、params 的冻结逻辑分散在两处:

  1. setCurrentRoute --- 手动冻结 meta 和 query
  2. createStartLocation --- 手动创建冻结的初始对象
typescript 复制代码
// 优化前:setCurrentRoute 中
function setCurrentRoute(route: RouteLocation): void {
	const from = currentRoute
	currentRoute = {
		path: route.path,
		name: route.name,
		meta: Object.freeze({ ...route.meta }), // 手动冻结
		query: Object.freeze({ ...route.query }), // 手动冻结
		params: Object.freeze({ ...route.params })
		// ...
	}
}

// 优化前:createStartLocation 中
export function createStartLocation(): RouteLocation {
	return {
		path: '/',
		meta: Object.freeze({}), // 手动冻结
		query: Object.freeze({}), // 手动冻结
		params: Object.freeze({}) // 手动冻结
		// ...
	}
}

这种分散存在两个问题:

  1. 重复代码 --- 冻结逻辑在多处重复,后续若需条件冻结(如开发模式跳过冻结),需改多处
  2. 不一致风险 --- 新增字段时容易遗漏冻结

优化方案

将冻结逻辑集中到 createRouteLocation 工厂函数中:

typescript 复制代码
// 优化后:createRouteLocation 中统一冻结
export function createRouteLocation(base: { path: string; name?: string; meta: RouteMeta; query: Record<string, string>; fullPath: string; params?: ParamObject; _synced?: boolean }): RouteLocation {
	const query = Object.freeze(base.query)
	const params: Readonly<ParamObject> = base.params ? Object.freeze({ ...base.params }) : Object.freeze({})
	return {
		path: base.path,
		name: base.name,
		meta: Object.freeze({ ...base.meta }),
		query,
		params
		// ...
	}
}

setCurrentRoute 和 createStartLocation 不再手动冻结,统一委托给 createRouteLocation:

typescript 复制代码
// 优化后:setCurrentRoute 中
function setCurrentRoute(route: RouteLocation): void {
	const from = currentRoute
	currentRoute = createRouteLocation({
		path: route.path,
		name: route.name,
		meta: { ...route.meta },
		query: { ...route.query },
		fullPath: route.fullPath,
		params: route.params,
		...(route._synced !== undefined && { _synced: route._synced })
	})
	// ...
}

// 优化后:createStartLocation 中
export function createStartLocation(): RouteLocation {
	return createRouteLocation({
		path: '/',
		meta: {},
		query: {},
		fullPath: '/'
	})
}

优化收益

维度 优化前 优化后
冻结逻辑位置 setCurrentRoute + createStartLocation createRouteLocation 一处
代码行数 分散在多处 集中在工厂函数
后续维护 改冻结策略需改多处 只需改 createRouteLocation
一致性 手动保证 工厂函数自动保证

升级指南

v1.6.1 是纯内部优化,完全向后兼容,无需修改任何现有代码即可升级。

本次优化不改变任何公共 API 的行为和签名,所有变更仅限于内部实现细节。如果你正在使用 v1.6.0,直接升级到 v1.6.1 即可享受性能提升。

相关推荐
风骏时光牛马1 小时前
后端服务接口开发与性能优化
前端
kyriewen1 小时前
我让 4 个 AI 互相 review 代码,最温柔的那个下手最狠
前端·程序员·ai编程
计算机魔术师2 小时前
493家公司白砸AI钱?Apollo这组数据戳破了幻觉
前端
IT_陈寒2 小时前
Java静态变量初始化坑得我头皮发麻
前端·人工智能·后端
柳杉2 小时前
用 Codex 完成智慧高速 3D 可视化大屏,从 18 张行业设计稿到可交互的运行监测中心
前端·ai编程·数据可视化
review445432 小时前
拿到 codex 第一步
前端·agent·vibecoding
鶴哥只手遮天3 小时前
jQuery 4.0 源码架构与工程实践-第 01 章 · 全景与工程结构:一个 20 岁库的自省
前端·javascript·jquery
徐小夕3 小时前
doc2docx方案,开源!
前端·vue.js·github
徐小夕3 小时前
JitOFD:一款面向信创与档案场景的 Web 端 OFD 编辑器
前端·vue.js·github
孟健4 小时前
Kimi K3.1 Pro 编程实测:3个月27万行代码,每年1.7万预算下如何9分钟修好顽固Bug
前端·开源·ai编程