在生产环境下,你真的有考虑到使用数组方法的健壮性吗?

场景

在一个风和日丽的清晨,刚进公司我就看到测试小哥眉头紧锁,疯狂的在工位上面摆弄自己的鼠标。突然抬头看到我进来,急急忙忙的说:火锅哥,快过来搂一眼!正式环境上突然图表的数据没了。昨天还好好的,今天早上领导突然要看效果,把链接一打开进入数据大屏就不行了。

看着测试要背锅的样子,只能帮忙排查一下问题呗! 如果是没有数据,那咱就先抓包看一下~

但是看到网络请求里面,后端所有数据都是正常返回的,为什么没渲染呢? 难道是前端代码报错导致打断了渲染?

咱从网络又切换到了控制台~ 好家伙果然是报错了。

然后马上打开了vscode,找到了这行代码的逻辑,如下:

原因就是res是后端接口的返回,按正常情况应该返回一个Array数组,结果实际返回了一个"null",那自然而然就JS报错了呗!

于是乎找到后端大佬说明了情况,谁知大佬这天来了大姨妈,心情及其暴躁~ 吼着说: 逻辑不会永远按正常情况返回,你前端不做代码健壮性处理?而且即使我返回的是null,与下面渲染逻辑有什么关系吗? 你该渲染还是渲染啊!

听到大佬这么回答,顿时我与测试都陷入了沉默。(JS的报错确实会打断后续逻辑的交付,大佬这么讲也没什么毛病)

测试:火锅哥,你改一下吧! 不然老板怪我没测出来,帮你点杯蜜雪呗!

我:行吧行吧~ 反正加一行判断的事~

改完准备发版的时候,后端大佬又来了一句,不只这里可能会返回null,其他的接口你也注意看一下哦!

听到大佬的这话,我彷佛天都要塌~ 那我的这个工作量太大了!每个都要去加判断呀,由于当时项目急着上线,很多这种接口的地方,都没做容错处理。

想到以后所有的项目都是找大佬对接接口,如果每次写代码都这样写,或者有稍微一不注意漏掉的地方,下次测试就直接给我提BUG了,这点逼绩效全部都要扣完。

于是乎我决定造一个轮子工具,针对处理数组的轮子工具,即使类型不是数组,也不能出现报错打断的情况。让逻辑继续走,顶多报一个警告提示出来,后续再处理!

safe-array-utils诞生,源码如下:

js 复制代码
class SafeArrayWrapper {
  #array;
  constructor(input, error) {
    let array = [];
    const rawType = Object.prototype.toString.call(input);
    //首先做类型的判断:
    //1.如果是数组就不管,直接赋值
    //2.如果是类数组,就直接转换成数组
    //3.如果是其他类型,就直接抛警告 
    //4.最后不是数组类型的数据,全部赋值为空数组
    if (Array.isArray(input)) {
      array = input;
    } else if (
      rawType === '[object Arguments]' ||
      (typeof input === 'object' && input !== null && 'length' in input)
    ) {
      try {
        array = Array.from(input);
      } catch (e) {
        console.warn(`[SafeArray] 类数组转换失败`);
      }
    } else {
      console.warn(`[SafeArray] 输入不是合法数组或类数组。类型:${rawType},定位标记:${error || '无'}`);
    }

    this.#array = array;
  }
  

  //下面就是针对数组原型上面一些方法的操作了,保留原数组原型方法的特性

  static chainableMethods = ['map', 'filter', 'slice', 'concat', 'flat', 'flatMap', 'reverse', 'sort'];
  static terminalMethods = [
    'join', 'reduce', 'find', 'findIndex', 'includes',
    'indexOf', 'lastIndexOf', 'every', 'some', 'at',
    'toString', 'toLocaleString'
  ];

  static allowedMethods = [...this.chainableMethods, ...this.terminalMethods, 'value'];

  static #proxyMethod(methodName) {
    return function (...args) {
      const target = this.#array;

      if (typeof target[methodName] !== 'function') {
        console.error(`数组不存在名为 "${methodName}" 的方法`);
        return this;
      }

      const result = Array.prototype[methodName].apply(target, args);

      if (SafeArrayWrapper.chainableMethods.includes(methodName)) {
        return new SafeArrayWrapper(result).#array;
      } else {
        return result;
      }
    };
  }

  value() {
    return [...this.#array];
  }

  static {
    for (const method of this.allowedMethods) {
      this.prototype[method] = this.#proxyMethod(method);
    }
  }
}

function SafeArray(input, error) {
  return new SafeArrayWrapper(input, error);
}

export default SafeArray;

其实整个轮子的核心逻辑就是,类型是数组就还是走数组方法的操作,类型不是数组就抛出警告,同时把传入的值赋值为空数组。

同时为了使用方便,我把它打成了一个npm包,包名就叫:safe-array-utils

1.正常用法:

js 复制代码
 import SafeArray from 'safe-array-utils'
 let arr = [1,2,3,4]
 
 //与使用数组方法一样,只是把数组包裹一层函数调用
 SafeArray(arr).forEach(el=>{
    console.log(el)
 })
 let newArr = SafeArray(arr).map(el=>{
    return el * 2
 })
 
 //同时也支持链式调用
   let arr2 = [1,2,3,4,undefined]
  let newArr = SafeArray(arr2).filter(_=>_).map(el=>{
    return el * 2
 })
 
 //包括其它的数组方法,如
 let arr2 = [1,2,3,4]
 SafeArray(arr2).at(1)
 SafeArray(arr2).join('-')
 

2.如果传入错误类型

js 复制代码
//即使传的类型不对,也不会报错了。更不会打断下面的逻辑
 let newArr = SafeArray('null').map(el=>{
    return el * 2
 })
 console.log(newArr) // 空数组 []
 console.log('正常打印')
 

3.假如页面多处地方用到

js 复制代码
    //可以传第二个参数,加一个标记定位
    SafeArray('null','第一处').map(el => {
      return el * 2
    })
    SafeArray('null','第二处').map(el => {
      return el * 2
    })
    SafeArray('null','第三处').map(el => {
      return el * 2
    })
  

怎么样,兄弟们~ 没有什么事是不能用造1个轮子解决的。如果有,那就造2个!

总结:

还是回到最初的问题,即使后端没按照数组的方式返回结果,我们也能正常走后续的逻辑,从而不会因为页面报错,影响页面上的其他功能。最后我想请问家人们你们平时写代码会注重代码的健壮性吗? 我想如果是项目工期短,时间紧。会很少有人关注这一块,甚至现在还有很多小公司不会去做单元测试。如果该文章对你有帮助,就请点赞+收藏吧!如果你们项目中也遇到这种情况。你会使用哪种方式去做呢?欢迎留言讨论~

相关推荐
独行soc1 小时前
2025年渗透测试面试题总结-98(题目+回答)
网络·安全·web安全·adb·面试·渗透测试·安全狮
golang学习记1 小时前
从0死磕全栈之Next.js App Router动态路由详解:从入门到实战
前端
huangql5201 小时前
基于前端+Node.js 的 Markdown 笔记 PDF 导出系统完整实战
前端·笔记·node.js
在逃的吗喽1 小时前
Vue3新变化
前端·javascript·vue.js
yqwang_cn1 小时前
打造优雅的用户体验:自定义jQuery工具提示插件开发全解析
前端·jquery·ux
小Tomkk1 小时前
AI 提效:利用 AI 从前端 快速转型为UI/UX设计师和产品
前端·人工智能·ui
Demoncode_y2 小时前
Vue3中基于路由的动态递归菜单组件实现
前端·javascript·vue.js·学习·递归·菜单组件
杨超越luckly2 小时前
HTML应用指南:利用POST请求获取全国中国工商农业银行网点位置信息
大数据·前端·html·数据可视化·银行网点
Never_Satisfied2 小时前
在JavaScript / HTML中,浏览器提示 “Refused to execute inline event handler” 错误
开发语言·javascript·html
Never_Satisfied2 小时前
在JavaScript / HTML中,事件监听的捕获和冒泡阶段解析
开发语言·javascript·html