导致性能问题的原因可能很复杂,也可能很简单,今天让我们来看一个现实的例子。一个多重循环导致列表卡死。
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);
}
虽然是一个简单低级的错误,但是错误实实在在发生在身边,在数据量小的时候可能任何写法都没有区别,随着你的项目的成长,问题是逐步暴露的,只能一一解决。