实际工作相关
一、H5 页面如何进行首屏优化
1. 路由懒加载
- 适用于 SPA ( 不适用 MPA )
- 路由拆分,优先保证首页加载
2. 服务端渲染 SSR
传统的前后端分离( SPA )渲染页面的过程复杂
SSR 渲染页面过程简单,所以性能好
如果是纯 H5 页面,SSR 是性能优化的终极方案
SSR 是一门 “ 古老 ” 的技术
- 刚刚兴起 Web 1.0 时,就是 SSR 技术:PHP ASP JSP 等
- Nuxt.js(Vue)
- Next.js(React)

3. App 预取
如果 H5 在 App WebView 中展示,可使用 App 预取
用户访问列表时,App 预加载文章首屏内容
用户进入 H5 页,直接从 App 中获取内容,瞬间展示首屏

4. 分页
- 针对列表页
- 默认只展示第一页内容
- 上划加载更多
5. 图片懒加载 lazyLoad
- 针对详情页
- 默认只展示文本内容,然后触发图片懒加载
- 注意:提前设置图片尺寸,尽量只重绘不重排
6. Hybrid
提前将 HTML JS CSS 下载到 App 内部
在 App webview 中使用 file:// 协议加载页面文件
再用 Ajax 获取内容并展示(也结合 App 预取)

7. 划重点
- 服务端 SSR 是 H5 的终极优化方案(但成本也高)
- 移动端 H5 要结合 App 能力去优化
- 严格来说,hybrid 不是 H5,但这里回答出来没问题
8. 扩展
- 性能优化要配合分析、统计、评分等,做了事情要有结果
- 性能优化也需要配合体验,如骨架屏,loading 动画等
二、一次性返回 10w 条数据如何渲染
1. 设计不合理
- 后端返回 10w 条数据,本身技术方案设计就不合理
- 主动沟通此事
2. 浏览器能否处理 10w 条数据
- JS 没问题
- 渲染到 DOM 会非常卡顿
3. 自定义中间层
- 自定义 nodejs 中间层,获取并拆分这 10w 条数据
- 前端对接 nodejs 中间层,而不是服务端
- 成本比较高
4. 虚拟列表
只渲染可视区域 DOM
其他隐藏区域不显示,只用
<div>撑起高度随着浏览器滚动,创建和销毁 DOM
虚拟列表实现起来非常复杂,可借用第三方 lib( Vue-virtual-scroll-list React-virtualiszed )

三、文字超出省略
1. 单行文字
css
#box1 {
border: 1px solid #ccc;
width: 100px;
white-space: nowrap; /* 不换行 */
overflow: hidden;
text-overflow: ellipsis; /* 超出省略 */
}2. 多行文字
css
#box2 {
border: 1px solid #ccc;
width: 100px;
overflow: hidden;
display: -webkit-box; /* 将对象作为弹性伸缩盒子模型显示 */
-webkit-box-orient: vertical; /* 设置子元素排列方式 */
-webkit-line-clamp: 3; /* 显示几行,超出的省略 */
}四、前端常用的设计模式有哪些
1. 设计原则
- 最重要的思想:开放封闭原则
- 对扩展开放
- 对修改封闭
2. 工厂模式
用一个工厂函数,来创建实例,隐藏 new
如 jQuery $ 函数
如 React createElement 函数
js// 工厂模式 function factory(a, b, c) { // if else return new Foo() } const f = factory(1, 2, 3) // $('div') === new JQuery()
3. 单例模式
全局唯一的实例(无法生产第二个)
如 Vuex Redux 的 store
如全局唯一的 dialog modal
typescript// 单例模式 class SingleTon { private static instance: SingleTon | null = null private constructor() {} public static getInstance(): SingleTon { if (this.instance == null) this.instance = new SingleTon() return this.instance } fn1() fn2() } const s = new SingleTon() // 会报错 const s = SingleTon.getInstance() const s1 = SingleTon.getInstance() s === s1 // true扩展
- JS 是单线程的,创建单例很简单
- Java 是支持多线程的,创建单例要考虑锁死线程
- 否则多个线程同时创建,单例就重复了(多线程共享进程内存)
4. 代理模式
- 使用者不能直接访问对象,而是访问一个代理层
- 在代理层可以监听 get set 做很多事情
- 如 ES6 Proxy 实现 Vue3 响应式
5. 观察者模式
js
// 一个主题,一个观察者,主题变化之后触发观察者执行
btn.addEventListener('click', () => {})6. 发布订阅
js
// 绑定
event.on('event-key', () => {
// 事件一
})
event.on('event-key', () => {
// 事件二
})
// 触发执行
event.emit('event-key')- 温故而知新:绑定的事件要记得解除,防内存泄漏
7. 装饰器模式
- 原功能不变,增加一些新功能( AOP 面向切面编程)
- ES 和 TypeScript 的 Decorator 语法
- 类装饰器,方法装饰器
8. 划重点
- 经典设计模式有 23 个,这是基于后端写的,前段不是都常用
- 要结合应用场景
9. (连环问) 观察者模式和发布订阅模式的区别

- 观察者模式
- Subject 和 Observer 直接绑定,没有中间媒介
- 如 addEventlistener 绑定事件
- 发布订阅
- Publisher 和 Observer 互不认识,需要中间媒介 Event channel
- 如 EventBus 自定义事件
五、在实际工作中,做过哪些 Vue 优化
1. v-if 和 v-show
- v-if 彻底销毁组件
- v-show 使用 CSS 隐藏组件
- 大部分情况下使用 v-if 更好,不要过度优化
2. v-for 使用 key
html
<ul>
<!-- 而且,key 不要用 index -->
<li v-for="(id, name) in list" :key="id">{{ name }}</li>
</ul>3. 使用 computed 缓存
js
export default {
data() {
return {
msgList: [...] // 消息列表
}
},
computed: {
// 未读消息数量
unreadCount() {
return this.msgList.filter(item => item.read === false).length
}
}
}4. keep-alive 缓存组件
- 频繁切换的组件,如 tabs
- 不要乱用,缓存太多会占用内存,且不好 debug
5. 异步组件
- 针对体积较大的组件,如编辑器、复杂表格,复杂表单等
- 拆包,需要时异步加载,不需要时不加载
- 减少主包的体积,首页会加载更快
6. 路由懒加载
- 项目比较大,拆分路由,保证首页先加载
7. 服务端渲染 SSR
- 可使用 Nuxt.js
- 按需优化,使用 SSR 的成本比较高
8. 划重点
- 性能优化要按需进行,不要为了优化而优化
六、(连环问) 你使用 Vue 遇到哪些坑
1. 内存泄漏
- 全局变量,全局事件,全局定时器
- 自定义事件
2. Vue2 响应式的缺陷( Vue3 不再有)
- data 新增属性要用 Vue.set
- data 删除属性用 Vue.delete
- 无法直接修改数组 arr[index] = value
3. 路由切换时 scroll 到顶部
- SPA 的通病,不仅仅是 Vue
- 如:列表页,滚动到第二屏,点击进入详情页
- 再返回到列表页(此时组件重新渲染)就 scroll 到顶部
4. 路由切换时 scroll 到顶部 - 解决方案
- 在列表页缓存数据和 scrollTop 值
- 当再次返回列表页时,渲染组件,执行 scrollTo(xx)
- 终极方案:MPA + App WebView
5. 划重点
- 日常要注意记录总结,遇到坑就记录一下
七、如何统一监听 Vue 组件报错
1. window.onerror
- 全局监听所有 JS 错误
- 但它是 JS 级别的,识别不了 Vue 组件信息
- 捕捉一些 Vue 监听不到的错误
2. errorCaptured 生命周期
- 监听所有 下级 组件的错误
- 返回
false会阻止向上传播
3. errorHandler 配置
Vue 全局错误监听,所有组件错误都会汇总到这里
但 errorCaptured 返回 false ,不会传播到这里
js// main.js app.config.errorCaptured = (err, vm, info) => { console.log('errorCaptured') }
4. 异步错误
- 异步回调里的错误,errorHandler 监听不到
- 需要使用 window.onerror
5. 答案
- errorCaptured 监听下级组件错误,返回 false 阻止向下传播
- errorHandler 监听全局 Vue 组件错误
- window.onerror 监听其他 JS 错误,如异步
6. 划重点
- 实际工作中,三者要结合使用
- errorCaptured 监听一些重要、有风险组件的错误
- window.onerror 和 errorHandler 候补全局监听
7. 扩展
- Promise 为处理的 catch 需要 onunhandledrejection
八、H5 很慢,如何排查性能问题
1. 前端性能指标
- First Paint ( FP )
- First Contentful Paint ( FCP )
- DomContentLoaded ( DCL )
- Largest Contentfull Paint ( LCP )
- Load ( L )
2. Chrome devTools
- Performance 可查看上述性能指标,并有网页快照
- Network 可以查看各个资源的加载时间
3. Lighthouse
非常流行的第三方性能评测工具
支持移动端和 PC
安装( 或使用 Chrome 自带 )
shellnpm i lighthouse -g运行
shelllighthouse https://wwww.burt1025.cn --view --preset=desktop
4. 识别问题:哪里慢?

- 如果是网页加载慢
- 优化服务端硬件配置,使用 CDN
- 路由懒加载,大组件异步加载 - 减少主包的体积
- 优化 HTTP 缓存策略
- 如果是网页渲染慢
- 优化服务端接口(如 Ajax 获取数据慢)
- 继续分析,优化前端组件内部的逻辑
- 服务端渲染 SSR
- 持续跟进
- 性能优化是一个循序渐进的过程,不像 bug 一次性解决
- 持续跟进统计结果,再逐步分析性能瓶颈,持续优化