后端返回null,前端怎么处理?数据容错——不用过分相信外部数据
场景
我们在开发过程当中,总是会遇到因为数据原因,导致使用数组方法或者获取对象属性的时候报错。
xxx is not fuction
Cannot read property xxxx of undefined
因为这些错误,会导致直接页面打不开,所以我们一般会做一些容错处理,从而让页面可以正常打开。例如:&& 、三元运算符,甚至有时会看到 if 语句来处理。
常见方式
1 // response 是来自接口的数据 2 const response = { 3 code: 200, 4 msg: 'message', 5 data: { 6 total: 100, 7 page: 1, 8 pageSize: 10, 9 content: [] 10 } 11 } 12 13 const goodsList = response.data.content.forEach(() => {}) 14 const total = response.data.total
为了保证取data、content属性和使用forEach不报错,可能会这样做
1 const goodsList = response.data && response.data.content && response.data.content.forEach(() => {}) 2 const total = response.data && response.data.total
这样就初步完成了数据容错,但是代码过于冗余可读性差,而且 total 的值还会可能变成 Boolean 类型。
简单改进
只需要简单的两个处理,一个是解构,一个是给默认值
1 const { data = {} } = response 2 const { constent = [], total = [] } = data 3 goodsList.forEach(() => {})
解构是非常有必要的,增加代码可读性和扁平化数据
不过,但这里又有了新的问题。这个时候如果我得到数据如下的样子:
1 const response = { 2 data: null 3 }
那么解构就会报错 Cannot destructure property content
of 'undefined' or 'null'
默认值生效的条件是,对象的属性值严格等于undefined
上面代码中,属性data等于null,因为null与undefined不严格相等,所以是个有效的赋值,导致默认值 {} 不会生效。实际就成了如下的样子:
1 const { constent = [], total = [] } = null
因此我们得保证拿到的数据不能存在null,不然上面的代码就没意义了。
进一步改进
你可能在想和后端约定好不返回 null 就好了
但是不能过分相信外部数据,包括约定之后的
这种情况其实可以在封装axios 或者fetch的时候,在里面添加一个过滤的函数,把从接口拿到的数据过滤一下,过滤掉值为 null 的数据,或者是把为 null 的数据重新赋值为 undefined。
下面是过滤数据的函数
1 // 把获取到的数据过滤一遍 2 const replaceNull = (obj) => { 3 for (let key in obj) { 4 switch (Object.prototype.toString.call(obj[key]).slice(8, -1)) { 5 case 'Object': 6 replaceNull(obj[key]) 7 break; 8 case 'Array': 9 for (let i = 0; i < obj[key].length; i++){ 10 replaceNull(obj[key][i]) 11 } 12 break; 13 default: 14 if (obj[key] === null) obj[key] = undefined; 15 } 16 } 17 }
过滤之后,这个时候这种写法就没问题了
1 const { data = {} } = response 2 const { constent = [], total = [] } = data 3 goodsList.forEach(() => {})
当然如果你们有node作为中间层,前端视图层是可以放心的使用解构默认值的,比如 graphQl 这种。
结束语
前端数据容错处理是必须的,不能期待外部数据的格式就是自己想要的。不知道大家平时都是怎么处理的。