Angular 调试 —— 一个真实的多重循环导致的Bug

导致性能问题的原因可能很复杂,也可能很简单,今天让我们来看一个现实的例子。一个多重循环导致列表卡死。 

startDemo() {
    this.processing = true
    // 创建复杂数据结构
    const data = [];
    for (let i = 0; i < 5000; i++) {
      const innerArray = [];
      for (let j = 0; j < 5000; j++) {
        const innerObject:any = {};
        innerObject.value = Math.random();
        innerArray.push(innerObject);
      }
      data.push(innerArray);
    }

    // 循环嵌套循环处理数据
    _.forEach(data, (innerArray) => {
      _.forEach(innerArray, (innerObject) => {
        innerObject.value = Math.pow(innerObject.value, 2);
      });
      innerArray = _.sortBy(innerArray, 'value');
    });

    // 模拟延迟以增加计算量
    setTimeout(() => {
      this.processing = false
    }, 2000);
  }

演示结果:

导致浏览器崩溃的问题在于:

首先,创建了一个非常大的数据结构,包含5000个内部数组,每个内部数组有5000个对象。这将占用大量的内存。

然后,在两个嵌套的 forEach 循环中,对数据进行处理。对于如此大规模的数据结构,这将导致非常高的计算负载,消耗大量的 CPU 资源和时间。

接下来,在延迟操作中使用了 setTimeout,将操作延迟了2秒。尽管这是为了模拟一个长时间运行的处理过程,但在这段时间内,浏览器将受到很大的压力,并且可能变得无响应或崩溃

如何优化呢:

1.减少数据规模:由于数据规模非常大,可以考虑减少内部数组的数量或对象的数量,以降低内存占用和计算负载。

2.分批处理:将数据分批处理,而不是一次性处理整个数据结构。可以使用分页或分块的方式,每次处理一部分数据,然后等待一段时间,再处理下一部分数据。这样可以避免长时间的单一计算任务对浏览器的影响。

3.使用 Web Workers:将数据处理和排序操作放在 Web Worker 中进行。Web Worker 可以在后台线程中执行代码,避免阻塞主线程,从而提高浏览器的响应性能。

4.优化算法和数据结构:如果可能的话,可以考虑使用更高效的算法和数据结构来进行数据处理和排序,以减少计算复杂度和提高性能。

优化后demo:(处理方式用的是分批处理)

startProcessing() {
    this.processing = true;
    this.currentPage = 0;

    this.data = [];
    for (let i = 0; i < 5000; i++) {
      const innerArray = [];
      for (let j = 0; j < 5000; j++) {
        const innerObject:any = {};
        innerObject.value = Math.random();
        innerArray.push(innerObject);
      }
      this.data.push(innerArray);
    }

    const pageSize = 100;
    this.numPages = Math.ceil(this.data.length / pageSize);

    const processPage = () => {
      const start = this.currentPage * pageSize;
      const end = Math.min((this.currentPage + 1) * pageSize, this.data.length);
      const pageData = this.data.slice(start, end);

      _.forEach(pageData, (innerArray) => {
        _.forEach(innerArray, (innerObject) => {
          innerObject.value = Math.pow(innerObject.value, 2);
        });

        innerArray = _.sortBy(innerArray, 'value');
      });

      this.currentPage++;

      if (this.currentPage < this.numPages) {
        setTimeout(processPage, 0);
      } else {
        this.processing = false;
      }
    };

    setTimeout(processPage, 0);
  }

 虽然是一个简单低级的错误,但是错误实实在在发生在身边,在数据量小的时候可能任何写法都没有区别,随着你的项目的成长,问题是逐步暴露的,只能一一解决。

猜你喜欢

转载自blog.csdn.net/KenkoTech/article/details/131443109