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 预取)
后端一次性返回 10W 条数据,应该怎么处理?
设计不合理:返回 10W 条数据,本身技术方案就不合理;
自定义中间层:自定义 node.js 中间层,获取并拆分这 10W 条数据.前端对接 nodejs 中间层,而不是服务端,但是成本比较高;
虚拟列表:只渲染可视区域 DOM,其他隐藏区域不显示,只用<div>撑起高度,随着浏览器的滚动,创建和销毁 DOM;使用插件Vue->virtual-scroll-list,React->virtualiszed
文字超出省略
//单行文字
#box{
border:1px solid #ccc;
width:100px;
white-space:nowrap;//不换行
overflow:hidden;
text-overflow:ellipsis;//超出省略号
}
//多行文字
#box{
border:1px solid #ccc;
width:100px;
overflow:hidden;
display:-webkit-box;//将对象作为弹性伸缩盒子模型显示
-webkit-box-orient:vertical;//设置子元素排列方式
-webkit-line-clamp:3;//显示几行,超出的省略
}
前端常用的设计模式和使用场景
设计原则:最重要的思想-开放封闭原则,对扩展开放,对修改封闭;
设计模式
-
工厂模式:用一个工厂函数,来创建实例,隐藏 new,如 JQuery 的$函数,React createElement 函数;
-
单例模式:全局唯一的实例(无法生成第二个),如 Vuex,ReactX 的 store,全局唯一的 dialog modal;
-
代理模式:使用者不能直接访问对象,而是访问一个代理层,代理层可以监听 get set.如 ES6 Proxy 实现 Vue3 的响应式;
-
观察者模式:例如 addEventListener;
-
发布订阅模式;
-
装饰器模式:原功能不变,增加一些新功能(AOP 面向切面编程),如:ES 和 TS 的 Decorstor 语法.类装饰器,方法装饰器(next.js)
观察者模式和发布订阅模式又什么区别?
观察者模式:Subject 和 Observer 直接绑定,没有中间媒介,如 addEventListener 绑定事件;
发布订阅:Publisher 和 Observer 互不认识,需要中间媒介 Event channel,如自定义事件;
在实际工作中,你做过那些 Vue 优化?
v-if 和 v-show:v-if 彻底销毁组件,v-show 使用 css 隐藏组件;
v-for 使用 key;
使用 computed 缓存:如:computed 缓存未读消息列表信息;
keep-alive 缓存组件:频繁切换的组件,如 tabs;
异步组件:针对体积较大的组件:编辑器,表格等.进行拆包,需要时加载,不需要则不加载,减少主包体积,加载更快些;
//vue3
import {defineAsyncComponent} from 'vue';
export default {
name:"AsyncComponent",
component:{
Child:defineAsyncComponent(()=>import(/*webpack打包*/,'./Child.vue'))
}
}
路由懒加载
服务端渲染 SSR:可以使用 Nuxt.js;
你使用 Vue 遇到过那些坑?
内存泄漏:全局变量,全局事件,全局定时器,自定义事件;
Vue2 响应式的缺陷:data 新增属性用 Vue.set;data 删除属性用 Vue.delete;无法直接修改数组 arr[index]=value;
路由切换时 scroll 到顶部:SPA 的通病,不仅 VUE,如:列表页,滚动到第二屏,点击进入详情页,再返回列表页(组件重新渲染)scroll 就到顶部;
解决方法:在列表页缓存数据和 scrollTop 值,当再次返回列表页时,渲染组件,执行 scrollTo(XX);终极方案:MPA+APP webView;
你实际工作中,做过那些 React 优化?
修改 Css 模拟 v-show:自定义变量控制显示隐藏;
循环使用 key;
使用 Fragment 减少层级;
JSX 中不要定义函数:JSX 会频繁执行,因此会频繁创建函数;(参考:for 比 forEach 更快)
要在构造函数中 bind this:要在构造函数中 bind this 而不是 JSX 中;或者使用箭头函数;
使用 shouldComponentUpdate:使用 shouldComponentUpdate 判断组件是否要更新,或者使用 React.PureComponent(对于数据的第一层进行比较),函数组件是有 React.memo;
Hooks 缓存数据核函数:useMemo,useCallback
异步组件;
路由懒加载;
SSR-next.js;
你使用 React 遇到过那些坑?
自定义组件的名称首字母要大写
JS 关键字的冲突:for 改为 htmlFor,class 改为 className;
JSX 的数据类型:{}内是 js 表达式,""是字符串(区别 vue);
setState 异步更新:更改数据后直接获取数据,还是原始值,应该用回调函数获取;
如何统一监听 Vue 组件的报错?
window.onerror:全局监听所有 JS 报错,但是它是 JS 级别的,识别不了 VUE 组件的信息,可以捕捉一些 VUE 监听不到的信息,try..catch...捕获的错误信息,不会上传到 window.onerror;
//msg:错误信息,source:错误文件,line:行,cilumn:列,error:错误的对象
window.onerror=function(msg,source,line,cilumn,error){
}
window.addEventListener('error',event=>{
})
<!-- 上面两种都可监听window.onerror -->
errorCaptured 生命周期:监听所有下级组件的错误,返回 false 会阻止向上传播;
errorCaptured(error,vm,info){
}
errorHandler 配置:Vue 全局错误监控,所有组件错误都会汇总到这里;
app.config.errorHandler=(error,vm,info)=>{
}
//与 window.onerro 互斥;
异步错误:在errorHandler中监听不到,需要用window.onerror监听;
如何监听 React 报错?
ErrorBoundary 组件:监听所有下级组件的报错,可降级展示 UI,只监听组件渲染时的报错,不监听 DOM 事件,异步报错.production 环境生效,dev 直接抛出错误;
//1.建文件 ErrorBoundary
//文件内容
import React from 'react';
class ErrorBoundary extends React.Component{
constructor(props){
super(props);
this.state={
error:null//存储当前的报错信息
}
}
static getDerivedStateFromError(error){
// 更新 state 使下一次渲染能够降级显示UI
console.info('getDerivedStateFromError',error);
return {error}
}
componentDidCatch(error,errorInfo){
//统计上报错误信息
console.info('componentDidCatch',error,errorInfo)
}
render(){
if(this.state.error){
//提示错误
return <div>报错了</div>
}
//没有错误信息,渲染子组件
return this.props.children
}
}
export default ErrorBoundary;
// 引入index.js 文件,包裹<app/>
事件报错:用 try...catch... window.onerror 监听;
异步事件:window.onerror 监听;
如果一个 H5 很慢,你该如何排查性能问题?
分析性能指标,找到慢的原因;
对症下药,解决问题;
持续跟进,持续优化;
前端性能指标
-
First Paint(FP):第一次渲染,可能没有东西
-
First Contentful Paint (FCP):第一次有内容的渲染,可以看到页面中的信息,哪怕是一个字
-
First Meaningful Paint(FMP)-已弃用,改为 LCP :第一次有意义的渲染
-
DomContentLoaded(DCL):页面的 DOM 加载完成;
-
Largest Contentfull Paint (LCP):页面最大的内容渲染完成;
-
Load(L):加载完成
使用 Chrome devTools:
-
Performance 可查看上述性能指标,并有网页快照;
-
Network 可查看各个资源的加载时间;
Lighthouse:第三方检测工具;
//使用:
npm i Lighthouse -g//全局安装
Lighthouse 网址 --view --preset=desktop //--view:需要评测报告 --preset=desktop:pc网页访问,默认H5访问
网页加载慢
优化服务器硬件配置,使用 CDN;
路由懒加载,大组件异步加载-减少主包的体积;
优化 HTTP 缓存策略;
网页渲染慢
优化服务端接口;
继续分析,优化前端组件内部的逻辑(参考 Vue,React 优化);
服务端渲染 SSR;
持续跟进
性能优化是一个循序渐进的过程,不像是一个 bug 一次性解决,持续跟进统计结果,再逐步分析性能瓶颈,持续优化;可使用第三方统计服务,如阿里云 ARMS,百度统计;
你在工作中,遇到过那些项目难点,如何让解决?
描述问题:背景+现象+造成的影响;
问题如何被解决:分析和解决;
自己的成长:学到了什么+以后如何避免;