是否存在在ES6中迭代大型数据集以避免浏览器超时的习惯用法?
假设我需要做一些像生成1600万个立方体或其他东西的东西,并且直接循环会超时浏览器。
function generateCubes(num) {
var cubes = [];
for (var ii = 0; ii < num; ++ii) {
cubes.push(generateCube());
}
return cubes;
}
var cubes = generateCubes(16000000);
所以我可以把它变成像这样的异步回调
function generateCubes(num, callback) {
var maxPerIteration = 100000;
var cubes = [];
function makeMore() {
var count = Math.min(num, maxPerIteration);
for (var ii = 0; ii < count; ++ii) {
cubes.push(generateCube());
}
num -= count;
if (count) {
setTimeout(makeMore, 0);
} else {
callback(cubes);
}
}
makeMore();
}
但遗憾的是我突然要重构我的所有代码
generateCubes(16000000, function(cubes) {
...
// all the code that used to be after cubes = generateCubes
});
我可以将其转化为基于承诺的东西,但这只会增加样板量。
在任何一种情况下,我都认为我可以写一个通用版本
function generateThings(factory, num, callback) {
var maxPerIteration = 100000;
var things = [];
function makeMore() {
var count = Math.min(num, maxPerIteration);
for (var ii = 0; ii < count; ++ii) {
things.push(factory());
}
num -= count;
if (num) {
setTimeout(makeMore, 0);
} else {
callback(things);
}
}
makeMore();
}
在这种特殊情况下,我正在生成1600万件事,这是一种迭代。也许接下来我想迭代这些事情。
function forEachAllThThings(things, op, callback) {
var maxPerIteration = 100000;
var num = things.length;
function doMore() {
var count = Math.min(num, maxPerIteration);
for (var ii = 0; ii < count; ++ii) {
op(things[ii]);
}
num -= count;
if (num) {
setTimeout(makeMore, 0);
} else {
callback();
}
}
doMore();
}
还有更多的ES6方式可以做到更简洁或更通用吗?
注意:请不要挂断生成多维数据集。那不是问题。此外,它不仅仅是关于超时问题,它也可能是一个混乱的问题。例如,我曾经在一个需要反序列化场景图的项目中工作过。中等复杂的图形可能需要5-10秒来反序列化(变成对象)。在那5-10秒内,浏览器被冻结了。
解决方案类似于上面的forEachAllTheThings
,因为我们只读取每个tick的N个对象,以免锁定浏览器。这是所有自定义代码。我只是想知道是否有一些新的ES6功能提供了任何类型的简化,解决了在多个 ticks 上做大量工作的问题,就像它们似乎简化了异步代码一样(因为这是感觉是一种异步代码形式)
根据@ Bergi关于宣传setTimeout
的建议,我认为这就是所建议的。
// returns a Promise that resolves in `time` millisecond
function sleep(time) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, time);
});
}
// returns a promise that resolves to an array of things
function generateThings(factory, num) {
var maxPerIteration = 100000;
var things = [];
function makeMore() {
var count = Math.min(num, maxPerIteration);
for (var ii = 0; ii < count; ++ii) {
things.push(factory());
}
num -= count;
return num ? sleep(0).then(makeMore) : things;
}
// we need to start off with one promise
// incase num <= maxPerIteration
return Promise.resolve(makeMore());
}
function generateCube() {
return Math.random(); // could be anything
}
generateThings(generateCube, 300000)
.then(function(things) {
console.log(things.length);
});
我认为,如果您的代码中已经有sleep
,那么它会略微ES6化并且会有几行变小(这似乎是一个合理的假设)。
答案 0 :(得分:2)
我可能会将多维数据集的生成卸载到web worker,它不会出现超时问题,假设多维数据集只包含JavaScript基本类型,因此可以发布到准备好后的主UI线程。理想情况下,多维数据集将为transferrable objects,因此您不必克隆它们,而是传输它们,从工作线程到主UI线程。