目录
前言
Vue-Router篇
1.Vue-Router导航守卫的完整执行流程
导航守卫流程一句话总结:"旧组件离开 -> 全局检查 -> 路由检查 -> 新组件进入"
假设从A页面跳转到B页面,路由守卫执行顺序如下:
- 失活:beforeRouteLeave(在失活组件中调用)
- 全局:router.beforeEach
- 重用:beforeRouteUpdate(如果组件被复用则调用它)
- 路由独享:beforeEnter
- 解析:解析异步路由组件
- 组件内:beforeRouteEnter(在被激活的组件里调用)
- 全局:router.beforeResolve(所有组件解析完)
- 全局:router.afterEach(跳转结束)
2.为什么beforeRouteEnter访问不到this
守卫执行时,新组件的实例还没有被创建,beforeRouteEnter是在导航之前被调用的,此时实例都没有被new出来,自然没有this
但是在beforeRouteEnter的next函数中,支持传入回调,这也是唯一一个支持在next中传递回调的守卫:
javascript
beforeRouteEnter(to, from, next) {
next(vm => {
// 这里的 vm 就是组件实例
console.log(vm.someData);
});
}
Vite篇
1.Vite为什么比Webpack快
核心区别在于"开发环境 "的启动方式 和热更新机制
启动一个项目时,Vite 与Webpack的区别如下:
Webpack:
- 必须先打包整个项目,构建依赖图,才能启动服务器
- 项目越大,启动越慢
Vite:
- 不需要打包,它直接启动服务器,利用浏览器原生的ES Module能力
- 当浏览器请求import时,Vite按需编译文件返回给浏览器
- 启动速度几乎是瞬间的
对于文件的热更新速度,区别如下:
- Webpack:修改一个文件,需要重新构建该模块及其依赖链,项目大了会有延迟
- Viet:修改文件后,只需让浏览器重新请求该文件编译后模块即可,热更新速度几乎不变
而在生产环境中,Vite使用Rollup打包,因为浏览器对大量嵌套ESM的网络请求性能依然不佳,此时两者的速度差异不如开发环境明显
2.什么是HMR(热更新)
HMR在应用运行时,只替换变更的模块,而不是刷新整个页面,从而保留应用的状态
底层原理(以Webpack为例,简要版):
- 监听:监听文件变化
- 构建:文件变动,重新编译
- 推送:向浏览器推送更新消息
- 请求:浏览器向服务器请求更新清单
- 替换:将旧模块替换成新模块
3.虚拟DOM一定比真实DOM快吗
不一定,需要分场景区分,下面是虚拟DOM比真实DOM快的一些场景:
- 大量数据更新或者复杂视图变化时
下面是虚拟DOM比真实DOM慢的一些场景:
- 首次渲染时:真实DOM只需要解析HTML即可渲染,而虚拟DOM需要解析代码、生成虚拟DOM树、Diff算法、创建真实DOM
- 极其简单的更新:例如只修改一个div的text
手写代码篇
1.手写数组扁平化flat
- 场景:把[1,[2,[3]]]变成[1,2,3]
- 附加要求:支持控制深度
javascript
Array.prototype.myFlat = function(depth = 1) {
let result = [];
this.forEach(item => {
if (Array.isArray(item) && depth > 0) {
result = [ ...result, ...item.myFlat(depth - 1), ];
}
else {
result.push(item);
}
})
return result;
}
const arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.myFlat(1)); // [1, 2, 3, 4, [5, 6]]
2.手写Promise.retry(请求重试)
- 场景:接口不稳定,如果失败了,自动重试3次,每次间隔1秒
javascript
function retry(fn, times, delay) {
return new Promise((resolve, reject) => {
function attempt() {
fn().then(resolve).catch(err => {
console.log("还有" + (times - 1) + "次机会");
if (times > 1) {
times--;
setTimeout(attempt, delay);
}
else {
reject(err);
}
})
}
attempt();
})
}
// 模拟一个可能失败的异步函数
function unstableAsyncFunction() {
return new Promise((resolve, reject) => {
const success = Math.random() > 0.5;
setTimeout(() => {
if (success) {
resolve("成功了!");
} else {
reject("失败了!");
}
}, 500);
});
}
// 使用 retry 函数
const f = retry(unstableAsyncFunction, 3, 1000)
.then(result => {
console.log("最终结果:", result);
})
.catch(error => {
console.error("最终失败:", error);
});