前端线上问题的那些事儿

本文主要介绍我们是如何处理前端线上问题的,希望能够帮助到大家。

文章先介绍常见的线上问题以及对应的解决方案,其次阐述了我们对整个项目流程做了哪些优化。

线上问题分类

线上问题多种多样,这里将分门别类介绍给大家。

无兜底

无兜底有很多种,包括但不限于:

•对象为 null 或 undefined 报错,常见于根据接口渲染页面

javascript 复制代码
Object.keys(obj); // 需要为 obj 增加兜底值 {},即 obj || {}

•数组为 null/undefined 报错,常见于根据接口渲染页面

c 复制代码
data.map(() => {...}) // 需要为 data 增加兜底值 [],即 data || []

•对 null/undefined 解构报错

arduino 复制代码
const { name } = obj; // 需要为 obj 增加兜底值 {},即 obj || {}

•页面中某个字段显示为 null(可能是接口返回的)

css 复制代码
<div>
  <div>价格:</div>
  <div>{data.count || 0}</div> {/* 增加兜底文案,比如短横杠 '-',0 等 */}
</div>

•图片加载失败,显示错误图片

ini 复制代码
{/* 使用兜底图替代;在图片的 onError 事件里也添加上兜底图片 */}
<img src={data.img || defaultImg} alt="" onError={handleError} />

•接口返回的链接为 null

javascript 复制代码
{/* 链接为 null 时处理成点击不跳转 */}
{res.link ? <div onClick={() => (location.href = res.link)}>xxx</div> : <div>xxx</div>}

•接口某些字段返回 null,前端又没设置容器尺寸,导致样式错乱,应该提前为容器设置尺寸占位

无兜底场景远远不止这些,不再一一列举。根据以往经验,兜底宁多勿少,否则轻则样式走样,重则页面白屏,引起客诉。

变量为空判断

这个问题非常非常常见,也很容易被遗忘,最高效的做法就是为变量增加 ?.

?. 是 ES6 提供的链判断运算符,避免报错,变量不存在时返回 undefined

kotlin 复制代码
res?.name // obj 是接口返回的对象(map),可能是 null
data?.length // arr 是接口返回的数组(list),可能是 null

兼容性

兼容性一直是前端同学诟病的一个问题,虽然早期的 IE 已经退出历史舞台,但随着移动端的兴起,低版本的手机浏览器又成了大家吐槽的对象,所以兼容性还是不能视而不见的。这里举几个我们遇见的例子:

•JS:location,在低版本浏览,如 Android 8.0 中会"找不到此对象"报错,需要增加 window.location

•JS:Promise.allSettled,在 67 以下的 Chrome 浏览器中无法适配,需要增加降级方法

•CSS:nth-last-child,不兼容 IE11,对于需要兼容 IE 的项目需要注意

查看 API 兼容性可戳 caniuse.com/

体验

前端是直接面向客户的,用户体验至关重要,体验做的不好,很有可能会造成客诉,比如:

•一个列表耗时 10+ 秒甚至更久也没加载出来,页面也没有"加载中"提示,客户会以为网站出错了,直接投诉,事实上是请求接口太慢,如果增加个 loading 提示,就不会让客户误会了。

•接口有错误信息返回时,页面无提示,客户就会很疑惑,极有可能投诉。一般的解决方案是,在统一封装的接口请求方法中,集中处理错误提示。

架构设计

•自动化配置预发和生产接口域名,即生产环境接口使用生产域名,预发环境接口使用预发域名

•调试工具 vConsole 等,切勿带到生产环境中

减少影响范围

减小影响范围,会间接降低线上事故率。

•使用 react-error-boundary

react-error-boundary 是 React 一个很香的发明,用过的都说好,他能保证页面不会因为某个模块出错而无法访问。Vue 中对应的是 errorCaptured 生命周期。

•内嵌系统的处理

有些项目是被内嵌到其他项目中使用的,被嵌入的项目存在差异化,包括主题、功能等,当其中某个项目有需求变更时,就要考虑是否会影响其他项目。

我们的解决方案是对各个被接入的项目进行归类,每类都新建不同的文件或路由,实现解耦,当某一类有需求变更时,只修改相应分类的文件。如果需求涉及到多个类,可以再抽离出公共小组件。

其他

剩下的我都放在其他里了。

•一个项目有人员变更再正常不过了,恰好以前的代码逻辑又非常复杂,各种 if else,根本不敢动。假如有新的需求,最稳妥的方法是新增判断分支,而不是修改以前的分支,除非你有十分的把握,否则改一下就是个线上事故。

•需要展示一段文本时,要有文本溢出的敏感度,因为文本可能只有英文字母或数字,需要添加额外的样式处理:

kotlin 复制代码
p {
    word-break: break-all
}

•节流&防抖

文本框输入,表单提交时要形成条件反射,考虑是否需要增加防抖。

监听 scroll 或 drag 事件时也要问问自己,是否需要增加节流。

•封装的必要性

记得在某个项目中,有段代码在不同文件中被重复写了 3 次,在一次需求中,恰好需要修改这些代码,但是研发只识别到了两处,结果偏偏用户就命中了第三处,引起了客诉。试想,如果把这三处封装在一起,不就很容易避免这次事故了吗?

流程优化

流程优化贯穿整个开发流程。

重视 CR

CR(Code Review) 能提前发现很多非业务问题,比如是否增加了兜底,是否增加了防抖、节流等。

CR 的时间建议安排在提测后。

建议每个团队都输出自己的 CR 规范,既统一了大家的代码风格,又能节省 CR 时间,更重要的是能避免一批线上问题。

前期做好监控

监控能让研发对问题先知先觉,有效避免很多客诉,90% 的问题都应该通过监控发现。

监控平台可配置以下告警:

•用户性能

•API 请求

•JSError

•资源

•自定义监控

•白屏

测试

•测试已发布静态资源

正常情况下,项目的测试工作都会在预发环境上进行,预发环境和生产环境有一模一样的配置,目的就是严格模拟生产环境,降低真正上线后的风险。

单页应用的上线顺序,一般是先发布静态资源,然后再修改模版(html)里的静态资源版本号。

这里建议大家,发布完静态资源后,在预发环境上测试下线上的静态资源,提前发现一些潜在问题。

•自测

自测是开发人员的基本素质,不自测就交给测试童鞋是可耻的。自测能发现测试童鞋遗漏的问题,自测能发现和修复代码中的错误、问题和潜在的缺陷,有效避免线上问题,所以要增加自测的重视度。

回滚

一旦遇到线上问题,第一时间就是回滚,回滚,回滚,重要事情说三遍。不要着急去找问题原因,很多同学都会陷入这种惯性思维,可能 Ta 们感觉很快就能找到问题原因吧,但是往往很多时候都事与愿违,造成很多客诉,甚至损失,最后不得已再回滚。既然如此,何必当初,早回滚不得了,要分清事情的轻重缓急。

对照现实中的例子,假如你看到你的朋友和陌生人发生了肢体冲突,被打的头破血流,你第一时间会去问他们发生冲突的原因吗?肯定不会呀,相反你会先把你朋友送到医院,等确定他脱离危险后,才会再追问他们冲突的原因。因为你知道,你朋友的命更重要。

同样的道理,现实中很清醒,到了工作中为啥就糊涂了呢?

复盘

复盘是一种很好的习惯,既能分享成功的经验,又能总结失败的教训。

出现了线上事故并不可怕,可怕的是反反复复。为了避免团队内部类似事情的重复发生,团队 leader 需要及时组织大家一起复盘,最好约个线下会议室,让大家都详细的了解事情的来龙去脉,才能在一定程度上有效的避免这类错误。会议结束后,也要做好会议纪要,以备警醒。

最后,非常期待大家在评论区也晒出你们遇到的前端线上问题,共同学习,让线上环境更稳定。

相关推荐
拾光拾趣录18 分钟前
CSS常见问题深度解析与解决方案(第三波)
前端·css
徊忆羽菲26 分钟前
Echarts3D柱状图-圆柱体-文字在柱体上垂直显示的实现方法
javascript·ecmascript·echarts
轻语呢喃35 分钟前
JavaScript :字符串模板——优雅编程的基石
前端·javascript·后端
杨进军36 分钟前
React 协调器 render 阶段
前端·react.js·前端框架
中微子39 分钟前
Blob 对象及 Base64 转换指南
前端
风铃喵游39 分钟前
让大模型调用MCP服务变得超级简单
前端·人工智能
中微子40 分钟前
智能前端实践之 shot-word demo
前端
归于尽41 分钟前
智能前端小魔术,让图片开口说单词
前端·react.js
用户98738245810141 分钟前
vite 插件
前端
Codebee42 分钟前
50行代码搞定OneCode摄像头插件:快速定制实战指南
前端框架·开源·ecmascript 6