function generateRoutes() {
return new Promise<RouteRecordRaw[]>((resolve, reject) => {
MenuAPI.getRoutes()
.then((data) => {
const dynamicRoutes = parseDynamicRoutes(data);
routes.value = [...dynamicRoutes];
isRoutesLoaded.value = true;
resolve(dynamicRoutes);
})
.catch((error) => {
reject(error);
});
});
}
这个方法是用来动态生成前端路由的异步函数。让我详细解释它的作用:
功能说明
- 异步获取路由配置:通过
MenuAPI.getRoutes()
从后端API获取路由数据 - 解析路由数据:将后端返回的数据转换为前端可用的路由格式
- 更新应用状态:将生成的路由保存到应用中并标记路由已加载
代码流程
function generateRoutes(): Promise<RouteRecordRaw[]> {
return new Promise((resolve, reject) => {
// 1. 调用API获取路由数据
MenuAPI.getRoutes()
.then((data) => {
// 2. 解析后端返回的路由数据
const dynamicRoutes = parseDynamicRoutes(data);
// 3. 更新本地状态(可能是Vue reactive变量)
routes.value = [...dynamicRoutes];
isRoutesLoaded.value = true;
// 4. 返回解析后的路由
resolve(dynamicRoutes);
})
.catch((error) => {
// 错误处理
reject(error);
});
});
}
使用场景
这种方法常用于:
- 权限管理系统:根据不同用户角色返回不同的可访问路由
- 动态菜单:根据用户权限动态生成侧边栏菜单
- 微前端架构:动态加载子应用的路由
类型说明
-
RouteRecordRaw
:通常是Vue Router的路由记录类型 -
routes.value
:暗示使用了Vue的ref或类似响应式状态管理 -
isRoutesLoaded.value
:用于标识路由是否已加载完成的标志
调用示例
// 在路由守卫或应用初始化时调用
generateRoutes()
.then((routes) => {
// 将动态路由添加到路由器中
router.addRoute(routes);
})
.catch((error) => {
console.error('路由加载失败', error);
});
这是一个典型的前端动态路由解决方案,实现了路由的按需加载和权限控制。
(resolve, reject)
参数的作用
这两个参数是 Promise 构造函数自动提供的回调函数:
-
resolve
:成功时调用,将 Promise 状态变为fulfilled
(已完成) -
reject
:失败时调用,将 Promise 状态变为rejected
(已拒绝)
如果不加 resolve(dynamicRoutes)
的后果
1. Promise 永远处于 pending 状态
// 调用这个函数后:
generateRoutes().then(routes => {
console.log('这里永远不会执行'); // ❌ 不会执行
}).catch(error => {
console.log('这里也不会执行'); // ❌ 不会执行
});
2. 内存泄漏
- Promise 永远不会被解决,相关的内存无法被垃圾回收
- 所有等待这个 Promise 的代码都会被阻塞
3. 路由无法使用
// 应用初始化代码
async function initApp() {
await generateRoutes(); // ❌ 这里会永远等待
router.addRoute(dynamicRoutes); // ❌ 永远不会执行
app.mount('#app'); // ❌ 应用无法正常挂载
}
4. UI 界面卡住
- 加载动画会一直显示
- 用户看不到任何内容
- 应用看起来像是"卡死了"
正确的 Promise 使用方式
function generateRoutes() {
return new Promise((resolve, reject) => {
MenuAPI.getRoutes()
.then((data) => {
const dynamicRoutes = parseDynamicRoutes(data);
routes.value = [...dynamicRoutes];
isRoutesLoaded.value = true;
// 必须调用 resolve!否则 Promise 永远不会完成
resolve(dynamicRoutes);
})
.catch((error) => {
// 也必须调用 reject!否则错误会被吞掉
reject(error);
});
});
}
简化写法(推荐)
其实可以不用 new Promise
,直接返回 API 调用:
async function generateRoutes() {
try {
const data = await MenuAPI.getRoutes();
const dynamicRoutes = parseDynamicRoutes(data);
routes.value = [...dynamicRoutes];
isRoutesLoaded.value = true;
return dynamicRoutes;
} catch (error) {
throw error; // 自动 reject
}
}
总结:不加 resolve()
会导致 Promise 永远处于等待状态,整个异步流程会被阻塞,应用无法正常工作。
resolve(dynamicRoutes); 可以把dynamicRoutes 换成 其它值
可以,但要注意类型和用途
是的,resolve(dynamicRoutes)
中的 dynamicRoutes
可以替换为其他值,但需要考虑以下几个方面:
1. 类型必须匹配
// 函数声明指定了返回 Promise<RouteRecordRaw[]>
function generateRoutes(): Promise<RouteRecordRaw[]> {
return new Promise<RouteRecordRaw[]>((resolve, reject) => {
// 必须返回 RouteRecordRaw[] 类型或兼容的类型
resolve(dynamicRoutes); // ✅ 正确
resolve([]); // ✅ 空数组也是 RouteRecordRaw[]
resolve([{ path: '/', component: Home }]); // ✅ 直接传数组
});
}
2. 可以返回的值示例
✅ 允许的返回值:
// 返回空数组
resolve([]);
// 返回静态路由
resolve([{ path: '/home', component: Home }]);
// 返回处理后的数据
resolve(processRoutes(data));
// 返回固定的路由结构
resolve([{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue')
}]);
❌ 不允许的返回值:
resolve(null); // ❌ 类型不匹配
resolve("字符串"); // ❌ 类型不匹配
resolve({}); // ❌ 对象不是数组
resolve(undefined); // ❌ 类型不匹配
3. 实际应用场景
场景1:返回空路由(无权限时)
resolve([]); // 用户没有任何权限时返回空数组
场景2:返回默认路由
resolve([{
path: '/no-permission',
component: NoPermission
}]);
场景3:返回处理后的数据
const filteredRoutes = dynamicRoutes.filter(route =>
hasPermission(route.meta?.permission)
);
resolve(filteredRoutes);
4. 完整示例
function generateRoutes(): Promise<RouteRecordRaw[]> {
return new Promise((resolve, reject) => {
MenuAPI.getRoutes()
.then((data) => {
if (!data || data.length === 0) {
// 没有数据时返回空数组
resolve([]);
return;
}
try {
const dynamicRoutes = parseDynamicRoutes(data);
// 过滤有权限的路由
const accessibleRoutes = dynamicRoutes.filter(route =>
checkPermission(route.meta?.permission)
);
routes.value = [...accessibleRoutes];
isRoutesLoaded.value = true;
// 返回过滤后的路由
resolve(accessibleRoutes);
} catch (error) {
// 解析出错时返回默认路由
resolve([{
path: '/error',
component: ErrorPage
}]);
}
})
.catch((error) => {
// API 调用失败时返回空数组
resolve([]);
// 或者 reject(error);
});
});
}
5. 最佳实践建议
- 保持类型一致:返回的值必须符合
RouteRecordRaw[]
类型 - 错误处理:在 catch 中也要调用 resolve 或 reject,避免 Promise 挂起
- 默认值:考虑在出错时返回合理的默认值而不是让 Promise 挂起
- 日志记录:如果返回非预期值,最好记录日志以便调试
总结:可以替换 dynamicRoutes
,但必须确保返回值的类型与函数声明的返回类型 Promise<RouteRecordRaw[]>
相匹配。