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

场景

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

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

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

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

然后马上打开了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个!

总结:

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

相关推荐
追逐时光者2 分钟前
面试第一步,先准备一份简洁、优雅的简历模板!
后端·面试
DoraBigHead4 分钟前
你写前端按钮,他们扛服务器压力:搞懂后端那些“黑话”!
前端·javascript·架构
前端世界41 分钟前
鸿蒙UI开发全解:JS与Java双引擎实战指南
javascript·ui·harmonyos
Xiaouuuuua1 小时前
一个简单的脚本,让pdf开启夜间模式
java·前端·pdf
@Dream_Chaser1 小时前
uniapp ruoyi-app 中使用checkbox 无法选中问题
前端·javascript·uni-app
深耕AI1 小时前
【教程】在ubuntu安装Edge浏览器
前端·edge
倔强青铜三1 小时前
苦练Python第4天:Python变量与数据类型入门
前端·后端·python
倔强青铜三1 小时前
苦练Python第3天:Hello, World! + input()
前端·后端·python
上单带刀不带妹1 小时前
JavaScript中的Request详解:掌握Fetch API与XMLHttpRequest
开发语言·前端·javascript·ecmascript
倔强青铜三2 小时前
苦练Python第2天:安装 Python 与设置环境
前端·后端·python