我创建了两个按钮。一个名为' sync'和其他名为' async'。点击同步'按钮,它应该使用循环处理大数组,它冻结浏览器,直到循环完成处理更大的数组。当我按下'async' button.it应该处理相同的大型数组而不冻结浏览器。如何使用setTimeOut函数执行此操作?
答案 0 :(得分:1)
您可以使用循环变量,如下面的代码。在此示例中,函数将每个元素增加1.超时时间为1毫秒。
var currentIndex;
function processNthElement(array) {
if (currentIndex >= array.length)
{
//the whole array has been processed, do what you need to do
//with the results here
return;
}
//do what you want with the array element here
array[currentIndex]++;
currentIndex++;
setTimeout(function () {
processNthElement(array);
}, 1);
}
function processArrayWithSetTimeout(array) {
currentIndex = 0;
processNthElement(array);
}
然后要处理一个大数组,只需调用processArrayWithSetTimeout(array)。但是,由于我们使用超时,您需要在最后一次函数调用时处理结果(请参阅函数中的注释)。如果数组有10000个元素,则处理时间超过10000毫秒或10秒,但UI不会被冻结。
请注意,这仍会按顺序处理数组,但在处理1个元素后等待一段时间后不会冻结UI。
答案 1 :(得分:0)
Javascript是单线程引擎。如此大的计算将暂时阻止所有其他事件。您可以使用Web worker在后台运行此类大脚本
答案 2 :(得分:0)
您可以使用递归,将setTimeout
声明为变量,以便能够“中断”对调用setTimeout()
的函数的递归调用
var curr, fn = (arr, i = -1, n = arr[++i]) =>
curr = setTimeout(() => {
// do stuf with `n`: current index in `arr` array
console.log(n);
// recursively call `fn` if condition met; e.g.,
// `i` less than `arr.length`
i < arr.length ? fn(arr, i) : (curr = void 0)
}, 0);
// e.g.
fn(Array(10000).fill(1));
// clear timeout, stop recursion
clearTimeout(curr);
答案 3 :(得分:0)
在ES7中使用异步/等待,这非常简单。耗时太长的长循环示例
function main() {
const numOperations = 1000000000;
let sum = 0;
for (let i = 0; i < numOperations; ++i) {
sum += doSomeOperation(i);
}
console.log(sum);
}
main();
function doSomeOperation(v) {
return v * 1.1 / (v + 1);
}
使用async / await使其偶尔出现在浏览器中的示例
async function main() {
const numOperations = 1000000000;
const iterationsPerChunk = 10000000;
let sum = 0;
for (let i = 0; i < numOperations; ++i) {
if (i % iterationsPerChunk === 0) {
await oneMoment();
}
sum += doSomeOperation(i);
}
console.log(sum);
}
main();
function doSomeOperation(v) {
return v * 1.1 / (v + 1);
}
function oneMoment() {
return new Promise((resolve) => {
setTimeout(resolve);
});
}
为iterationsPerChunk
选择一个好的值可能会更困难。您可以轻松地创建一些类来检查performance.now
并仅在经过一定时间(例如1/2秒或1秒)后才等待调用。每次致电setTimeout
都会产生5毫秒到20毫秒的时间,因此您不想等待太久,但是确实使它易于使用。