文章目录
考察重点
- 性能优化,错误监控
- 设计模式的应用
- 项目难点,角色之间的沟通
Vue 应该如何监听 JS 报错 ?
- 全局错误捕获(全局监听)a. Vue.config.errorHandler在 Vue 实例初始化之前,可以通过配置 Vue 的全局错误处理器 Vue.config.errorHandler 来捕获整个应用程序中的未处理错误。
- 生命周期钩子 errorCapturedVue 2.x 提供了一个实例级别的错误捕获钩子 errorCaptured,可以在组件树的任何地方捕获和处理错误
- window.onerror 和 window.addEventListener(‘error’)对于非 Vue 组件内部引发的全局错误,可以监听全局的 window.onerror 事件
- Vue 3.x 的全局异常捕获在 Vue 3.x 中,可以使用 app.config.globalProperties.$onError
// 1. 全局错误捕获(全局监听)a Vue.config.errorHandler在 Vue 实例初始化之前,可以通过配置 Vue 的全局错误处理器 Vue.config.errorHandler 来捕获整个应用程序中的未处理错误。
import Vue from 'vue';
Vue.config.errorHandler = function (err, vm, info) {
// err:错误对象
// vm:当前 Vue 实例
// info:Vue 特性相关的错误信息,如在 render 函数中发生的错误
console.error(err, info);
// 这里可以加入上报错误到服务器、显示错误提示等功能
};
// 2. 生命周期钩子 errorCapturedVue 2.x 提供了一个实例级别的错误捕获钩子 errorCaptured,可以在组件树的任何地方捕获和处理错误:Vue.component('YourComponent', {
// ...
errorCaptured(err, vm, info) {
// 同样可以在这里处理错误
console.error(err, info);
// ...
},
// ...
});
// 3. window.onerror 和 window.addEventListener('error')对于非 Vue 组件内部引发的全局错误,可以监听全局的 window.onerror 事件:window.onerror = function (errorMessage, fileName, lineNumber, columnNumber, error) {
// 处理错误逻辑
console.error(errorMessage, fileName, lineNumber, columnNumber, error);
};
// 或者使用 addEventListener
window.addEventListener('error', function(event) {
const { message, filename, lineno, colno, error } = event;
console.error(message, filename, lineno, colno, error);
// 错误处理逻辑
});
// 4. Promise 的 unhandledrejection 事件对于未处理的 Promise 拒绝,可以监听 window 的 unhandledrejection 事件:window.addEventListener('unhandledrejection', function(event) {
const reason = event.reason;
const promise = event.promise;
const handler = event.handledByCode ? 'handledByCode' : 'unhandled';
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
// 错误处理逻辑
});
// 5. Vue 3.x 的全局异常捕获在 Vue 3.x 中,可以使用 app.config.globalProperties.$onError:const app = createApp(App);
app.config.globalProperties.$onError = (err, instance, info) => {
// 处理错误逻辑
console.error(err, instance, info);
};
app.mount('#app');
你遇到了哪些项目难点?如何解决的?
描述问题:背景+现象+造成的影响
问题如何被解决:分析 + 解决
自己的成长:学到了什么 + 以后如何避免
你使用vue遇到过哪些坑?
- 路由切换时 scroll 到顶部
- SPA 的通病,不仅仅是 Vue
- 如列表页,滚动到第二屏,点击进入详情页
- 解决:在列表页缓存数据和 scrollTop 值,当再次返回列表页时,渲染组件,执行 scrollTo(xx)
- 路由切换时 scrol 到顶部
你在实际工作中,做过哪些vue优化
- v-if和v-show (算一个优化点,但实际工作中基本都用v-if,用不上v-show)
- v-for使用key (算一个优化点,但写代码时会强制你写上key,不写会报错)
- 使用computed缓存
- keep-alive缓存组件:
- 频繁切换的组件,如 tabs
- 不要乱用,缓存太多会占用内存,且不好 debug
- 异步组件
- 针对体积较大的组件,如编辑器、复杂表格,复杂表单等
- 拆包,需要时异步加载,不需要时不加载
- 减少主包的体积,首页会加载更快
- 路由懒加载
- 服务端渲染SSR
chatGPT回答
- 列表渲染优化
- 使用 v-for 时为每个循环项分配一个唯一的 key,确保Vue能够准确地跟踪每个节点的变化,从而更高效地进行DOM更新。
- 对于大型列表,考虑使用虚拟滚动(virtual scrolling)技术,只渲染可视区域内的元素。
- 组件懒加载
- 通过Vue的异步组件功能或者Webpack的动态导入功能,将非首屏显示的组件延迟加载,减少初次加载时的资源开销。
- 事件代理
- 在使用 v-for 渲染大量具有相同事件处理器的元素时,可以将事件委托到它们的父级元素上,避免为每个子元素单独绑定事件监听器。
- 状态管理与计算属性优化
- 合理划分组件状态,避免在不必要的地方过度依赖全局状态管理(如Vuex)
- 尽量利用计算属性(computed)缓存结果,减少重复计算。
- 代码分割与懒加载:
- 对路由配置进行懒加载设置,使得不同的路由对应的组件按需加载。
- 分离通用库和业务逻辑代码,合理使用代码分割实现按需加载JS和CSS资源。
- 资源优化
- 图片资源使用懒加载,只有当图片进入视窗时才开始加载。
- 使用GZIP压缩、CDN加速、文件最小化(minify)等方式优化静态资源。
- Vue实例优化
- 减少data对象中的属性数量,特别是不需要响应式的可以直接定义为普通对象或变量
- 注意避免在生命周期钩子中进行大量计算密集型或IO操作,可考虑异步处理
- Keep-Alive缓存
- 对于需要频繁切换但又不希望每次都重新渲染的组件,可以使用 组件进行缓存。
- SSR(Server-Side Rendering)与预渲染
- 对SEO要求较高的页面或者希望改善首屏加载速度的应用,可以采用服务端渲染(SSR)或静态预渲染(prerender-spa-plugin)
设计模式
设计原则: 最重要的思想:开放封闭原则,对扩展开放,对修改封闭
设计模式:
- 工厂模式
- 用一个工厂函数,来创建实例,隐藏 new
- 如 jQuery$ 函数
- 如 React createElement 函数
- 单例模式
- 全局唯一的实例(无法生成第二个)
- 如Vuex Redux 的 store
- 如全局唯一的 dialog modal
- 代理模式
- 使用者不能直接访问对象,而是访问一个代理层
- 在代理层可以监听 get set 做很多事情
- 如ES6 Proxy实现Vue3响应式
- 阮一峰es6入门 - proxy:Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
- 观察者模式:一个主题一个观察者,主题变化之后触发观察者执行
- 发布订阅模式:自定义on一个事件,emit触发
- 装饰器模式:
- 原功能不变,增加一些新功能(AOP 面向切面编程)
- ES 和Typescript的 Decorator 语法
- 类装饰器,方法装饰器
- 阮一峰es6入门 - 装饰器
// 工厂模式
class Foo { }
function factory(a, b, c) {
return new Foo()
}
const f = factory(1, 2, 3)
// 单例模式
class SingleTon {
private constructor() {}
public static getInstance(): SingleTon {
return new SingleTon()
}
fn1() {}
fn2() {}
}
const s = SingleTon.getInstance()
s.fn1()
s.getInstance() // 报错
// 观察者模式
btn.addEventListener('click',()=>{...})
// 发布订阅模式
event.on('event-key', fn1) // on绑定事件事件1 - mounted
event.on('event-key', fn2) // on绑定事件事件2
event.emit('event-key') // 触发执行
event.off('event-key', fn1) // beforeUnmount 时解绑,防止内存泄漏
// 装饰器模式
观察者模式和设计者模式的区别
- 观察者模式
- Subject和 Observer 直接绑定,没有中间媒介
- 如 addEventlistener 绑定事件
- 发布订阅
- Publisher 和 Observer 互不相识,需要中间媒介 Event channel
- 如 EventBus 自定义事件
后端返回10W条数据怎么渲染
- 设计不合理
- 虚拟列表:虚拟列表实现起来非常复杂,可借用第三方 lib,Vue-virtual-scroll-list,React-virtualiszed
- 只渲染可视区域 DOM
- 其他隐藏区域不显示,只用< div>撑起高度
- 随着浏览器滚动,创建和销毁 DOM
H5 页面如何进行 ** 首屏 ** 优化 ?
咱也没写过H5啊,为啥有这么多乱七八糟的东西
- 路由懒加载
- 适用于SPA(不适用于MPA)
- 路由拆分,优先保证首页加载
- 服务端渲染SSR
- 传统的前后端分离(SPA)渲染页面的过程复杂
- SSR 渲染页面过程简单,所有性能好
- 如果是纯 H5 页面,SSR 是性能优化的终极方案
- App 预取
- 如果 H5 在 App WebView 中展示,可使用 App 预取
- 用户访问列表页时,App 预加载文章首屏内容
- 用户进入 H5 页,直接从 App 中获取内容,瞬间展示首屏
- 图片懒加载 lazyLoad
- 针对详情页
- 默认只展示文本内容,然后触发图片懒加载
- 注意:提前设置图片尺寸,尽量只重绘不重排
- Hybrid
- 提前将 HTML JS CSS 下载到 App 内部
- 在 App webview 中使用 file://协议加载页面文件
- 再用 Ajax 获取内容并展示(也结合 App 预取 )
- 分页
- 服务端 SSR 是 H5 的终极优化方案(但成本也高),移动端 H5 要结合 App 能力去优化,严格来说,hybrid 不是 H5,但这里回答出来没问题