Skip to content

提升代码健壮性

一、优化工作流程

设计文档评审

推动团队进行设计评审,于公可以写出更加健壮的代码,于私可以快速提升研发能力

Code Review

设计评审是保证代码质量的第一步,但设计文档和最终代码实现之间仍然可能会有很大的差异,只有对即将合入的代码进行严格的Code Review,才能发现哪些仅在特定条件下发生的异常

严格自测

交叉测试

自动化测试

二、不要相信用户

用户是非常不可控的因素,他们的性格、习惯、对互联网的熟悉程度、对产品的熟悉程度等等都差别巨大. 最好通过合理的规则进行约束

不要相信用户的输入

要做适当的格式校验或者转义

不要相信用户的权限

  1. 全量路由配置 + 拦截鉴权
  • 每次鉴权实时调用用户最新权限。以性能换安全
  • 前端校验,后端更新时,将用户token过期,前端重新登录。以体验换安全
ts
const routes = [
    //全量的路由配置
]

const router = new Router({
    routes,
    mode: 'history'
});


router.beforeEach(async (to, from, next) => {
    //检查用户是否有将要跳转的路由权限
    if (await checkPermission(to)) {
        next();
    } else {
        //无权限处理,可以跳转到403页面
        next('/403');
    }
})
  1. 动态路由
ts
const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/login', component: Login }],
})

//获取用户权限
//根据权限添加有权限的路由
router.addRoute({ path: '/vip', component: Vip })

用户进入不存在的页面

  • 错误的地址,需要让用户跳转到404页面,可以通过nginx配置或者路由配置进行设置
  • 资源被删除,同上,或者根据需要单独配置
  • 老地址,兼容老地址,并配置跳转到新路由

不应该的按钮点击

  • 无权限按钮

指令封装

  • 禁用不可点击按钮,如,未填写完的表单

  • 防止重复点击,如,提交按钮,请求后给loading

三、"不相信"后端

考虑安全取值, res.data -> [] 但后端的默认值不一定是 []

四、不使用旧数据

表单同时编辑?

  1. 增加一个最后编辑字段 或 版本字段,后端校验是否一致
  2. 查询是否有人编辑
  3. 多人协同

五、不传递无用数据

PUT 类型,如修改 用户信息的 username

不应传整个 formData 这种情况可以合后端协商

六、错误捕获

JS 错误类型

  • RangeError

RangeError 对象表示一个特定值不在所允许的范围或者集合中的错误。

在以下的情况中,可能会遇到这个问题:

a. 将不允许的字符串值传递给 String.prototype.normalize() b. 尝试使用 Array 构造函数创建一个具有不合法的长度的字符串 c. 传递错误值到数值计算方法(Number.toExponential()、Number.toFixed() 或 Number.toPrecision())。

  • ReferenceError

ReferenceError(引用错误)对象代表当一个不存在(或尚未初始化)的变量被引用时发生的错误。

  • SyntaxError

SyntaxError(语法错误)对象代表尝试解析不符合语法的代码的错误。当 Javascript 引擎解析代码时,遇到了不符合语法规范的标记(token)或标记顺序,则会抛出 SyntaxError。

  • TypeError

TypeError(类型错误)对象通常(但并不只是)用来表示值的类型非预期类型时发生的错误。

以下情况会抛出 TypeError:

a. 传递给运算符的操作数或传递给函数的参数与预期的类型不兼容; b. 尝试修改无法更改的值; c. 尝试以不适当的方法使用一个值。

  • URIError

URIError 对象用来表示以一种错误的方式使用全局 URI 处理函数而产生的错误。

  • AggregateError

AggregateError 对象代表了包装了多个错误对象的单个错误对象。当一个操作需要报告多个错误时,例如 Promise.any(),当传递给它的所有承诺都被拒绝时,就会抛出该错误。

  • InternalError

InternalError 对象表示出现在 JavaScript 引擎内部的错误。

通常描述某种数量过多的情况,例如:

  • "too many switch cases"(过多 case 子句);

  • "too many parentheses in regular expression"(正则表达式中括号过多);

  • "array initializer too large"(数组初始化器过大);

  • "too much recursion"(递归过深)。

  • EvalError

此异常不再会被 JavaScript 抛出,但是 EvalError 对象仍然存在,以保持兼容性。

监听错误发生

捕获页面资源加载情况

捕获Vue组件中的错误

ts
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}

React组件ErrorBoundary

tsx
import { ErrorBoundary } from "react-error-boundary";

export function AddCommentContainer() {
  return (
    <ErrorBoundary fallback={<p>⚠️Something went wrong</p>}>
      <AddCommentButton />
    </ErrorBoundary>
  );
}

七、重视网络请求

后端接口再稳定,也挡不住用户网络异常等等原因,导致请求失败,因此要非常重视请求失败的处理。别忘记在请求失败后依然进行数据初始化。

ts
async function init(){
  try {
    let res = await getUserList();
    this.list = res.data || [];
  } catch (e) {
    //多考虑失败了如何处理
    this.list = [];
  }
}

关注慢速网络

尽量不要请求全量数据

别忘记取消网络请求

八、不忘记清除定时器

组件已经销毁,但是定时器未清除,那么定时器中对组件数据和DOM的操作可能就会产生问题,或者因为大量的定时器未清除导致内存溢出等问题。

九、前端监控(可选)

总结

健壮性是衡量代码质量的一个重要指标。

代码的异常来源有很多,用户的操作、API接口、权限、网络、缓存、浏览器、操作系统、服务器、自身代码的缺陷等,都会导致前端产生异常。

共 20 个模块,1301 篇 Markdown 文档。