《 关于我用拓展运算符把项目搞崩这件事 》

7,780 阅读4分钟

☀️ 前言

一个清风徐徐的晚上,月亮在飘渺的乌云中忽明忽暗,带着一种神秘的色彩,我在阳台吹着晚风刷着掘金。

  • 突然一个加急信息❗️❗️突如其来:快修Bug!
  • 老大:小卢,出大问题,你这段代码有问题,用户的软件崩溃了!!!
  • :不可能!绝对不可能!这代码在线上都一年了,要有问题早就出问题了。
  • 大家好我是小卢,前几天遇到一个很有意思的事情,一段在线上稳定运行一年多的代码把项目搞崩了。
  • 排查之后居然发现这段代码的提交人是我,我赶紧打开电脑想看看我一年前又写了什么弱智代码,却思索好一会没发现问题所在。

📍 定位问题

  • 删去所有业务代码并精简代码后,最后出问题的代码大概是这样的。
const items=[]
const newItems=getItemsById(id)||[]
items.push(...newItems)
  • getItemsById是根据id获取一个数组,在业务的特殊性上这里需要对一个数组合并另一个数组,有很多种数组合并的方法,当时选择了push
  • 乍一看,没问题啊,我本地也验证了好几次,根本不会引起报错啊更别说导致软件崩溃了。
  • 而且这样的写法其实也挺常见呀,更何况这一年来他根本没有出过任何问题,怎么可能是这里出错呢?
  • 难道这段代码随着时间会有什么变化? 时间。。。。 难道说随着用户用软件的时间增长,用户的数据增长了一定程度,这个数组的长度达到了一定极值之后爆栈了?
  • 赶紧模拟了用户数据巨大的情况下该代码的运行。
const items=[]
const newItems=new Array(1000000)
items.push(...newItems)
  • 我去!爆栈了,然后导致软件崩溃了!!

❓ 查其所以

  • 但是,为什么啊,为什么数组过长就会导致爆栈?是这个push的原因吗,还是因为拓展运算符?赶紧把这段ES6代码Babel在线转换一下。

  • 我们可以看到最后这段push拓展运算符数组的操作会变成push.apply(items, newItems)
  • 在查阅了MDN后终于知道了原因,如果按上面方式调用apply,有超出JavaScript引擎参数长度上限的风险。一个方法传入过多参数(比如一万个)时的后果在不同JavaScript引擎中表现不同。

  • 好家伙原来是因为这样,我做梦也没想到一个小小的拓展运算符push搭配时还会有这样的副作用,那么是不是在所有函数中如果使用拓展运算符传入参数超出一定数量就会如此呢?
  • 答案是:是的,如下图我随便写了个函数,使用拓展运算符传参,我们会发现它会自动转成使用apply方法,而在apply方法参数过多的时候就会引起爆栈,学到了学到了,这里是apply方法的介绍

🏄🏻 合理解决

  • 其实合并数组的有好几种方法,我们可以选择适合的方法去使用。
  • 使用concat合并。

  • 使用拓展运算符合并。

  • 循环push

  • 拓展运算符+push

  • 第二种应该是大家最常用的并且是最简便的,最后一种虽然数据量少的时候不会引起问题,但是还是少用吧哈哈,万一以后用户数据多起来了就会跟我一样收到一条加急❗️信息了。

👋🏻 写在最后

  • 这次分享了我在生活中真实遇到的有趣的事情,简单分析分享给大家,从一个·拓展运算符逐渐挖到apply方法,很多时候都有一些这样有趣的事情等着大家去发现,如果你有一颗好奇的心就会学到东西,希望对大家有帮助。
  • 如果您觉得这篇文章有帮助到您的的话不妨🍉🍉关注+点赞+收藏+评论+转发🍉🍉支持一下哟~~😛您的支持就是我更新的最大动力。
  • 如果想跟我一起讨论和学习更多的前端知识可以加入我的前端交流学习群,大家一起畅谈天下~~~

🌅 往期精彩

我被骂了,但我学会了如何构造高性能的树状结构🔥 243👍🏻

入职Apifox研发组三个月,我领悟了30个高效开发方法🔥 1146👍🏻

面试官:你觉得你最大的缺点是什么? 393👍🏻

几个一看就会的实用JavaScript优雅小技巧🌟 718👍🏻