深拷贝引发页面崩溃
问题所在:
很明显 out of Memory 导致的页面崩溃。也就是字面意思:内存不足。
不多BB直接上问题代码:
let detail = intervalDetail.intervalDetail;
Object.keys(this.selectList).forEach((item) => {
this.selectList[item].forEach((date) => {
const Dates = this.dataAll[item].find((item) => item.date === date);
const Index = this.dataAll[item].indexOf(Dates);
this.dataAll[item].splice(Index, 1, {
...Dates,
intervalDetail: JSON.parse(JSON.stringify(detail)),
limit_way: intervalDetail.limit_way,
limit_count: intervalDetail.limit_count,
room_count: intervalDetail.room_count,
});
});
});
问题出在 intervalDetail的复制哪里做了深拷贝,还是用JOSN的方法做的最原始的。但是由于这里的detail数据量很大,而且this.selectList也长度也不小,所以相当于要做1000+次拷贝。 ps:这里的深拷贝是由于需求做的。
思考:1.崩溃是由于深拷贝导致爆栈,内存溢出,或许可以换个方法。
import { cloneDeep() } from 'lodash-es';
cloneDeep(detail)
结果:然并卵,依旧蹦了。
思考:2.无法做深拷贝,是否可以换个方式达到目的。
intervalDetail: {
limit_count: detail.limit_count,
limit_type: detail.limit_type,
limit_way: detail.limit_way,
range: detail.range.map((item) => item),
},
利用map方法,直接吧需要拷贝的数组新建一份赋值。 实验:
let detail = {
limit_count: "2",
limit_type: "3",
limit_way: "5",
range: [
{ a: 1, b: 2, c: 3 },
{ a: 1, b: 2, c: 3 },
{ a: 1, b: 2, c: 3 },
{ a: 1, b: 2, c: 3 },
{ a: 1, b: 2, c: 3 },
{ a: 1, b: 2, c: 3 },
], //里面有超过2000+数据层级有2层
};
let arr = [];
console.log(new Date().getTime())
for (let i = 0; i < 1000; i++) {
// 直接深拷贝复制赋值
// arr[i] = JSON.parse(JSON.stringify(detail));
// 利用map赋值
arr[i] = {
limit_count: detail.limit_count,
limit_type: detail.limit_type,
limit_way: detail.limit_way,
range: detail.range.map((item) => item),
};
}
console.log(new Date().getTime())
直接赋值: 深拷贝: 两者速度明显不一样
思考:3.换种思路,不做深拷贝。
可以直接在一开始的时候直接数据赋值,虽然会有对象引用导致数据相关联,但是在用的时候可以再深拷贝复制一份重新赋值。这样也避免了很大的数据量拷贝,降低浏览器开销,避免崩溃。
结论
1.使用深拷贝要注意拷贝数据量的大小和层级,不然容易爆栈,内存不足
2.尽量不要使用JSON.parse(JSON.stringify(detail))来做深拷贝。 因为:
1.JOSN序列化把一些JS对象,比如日期,时间变为字符串,正则,Errer变空对象,函数,undefined会丢失,NaN,无穷大,等会被变为null
2.会丢失继承的属性,无法拷贝循环引用对象
3.换个思路解决问题,不要一条路走到黑。
转载自:https://juejin.cn/post/7081157927687421965