likes
comments
collection

深拷贝引发页面崩溃

作者站长头像
站长
· 阅读数 23
问题所在:

深拷贝引发页面崩溃 很明显 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.换个思路解决问题,不要一条路走到黑。