Javascript-等待超长循环的正确方式



也许这是一种异步/等待的情况,但我认为异步主要用于api调用(?(

你如何等待一个长循环才能完成,比如:

let x;
for (i = 1, i < 10000000000000000, i++) {
x += (i * 99999);
}
console.log(x);

我认为异步主要用于api调用(?(

有两个不同的概念与async单词有关:

  • async/await函数receive Promises的语法糖以同步方式产生结果
  • 实际异步行为XHR api调用、延迟执行、事件处理

async/await函数不会自动使函数执行异步。

const foo = async (i) => { console.log('foo running', i); return i == 0 ? 42 : await foo(i-1); };
console.log('foo before')
foo(5)
.then(x => console.log('foo', x))
console.log('foo after')
// foo before
// foo running 5
// foo running 4
// foo running 3
// foo running 2
// foo running 1
// foo running 0
// foo after
// foo 42

Javascript是一个线程,所有并发任务都必须拆分成异步块,才能有机会让其他任务工作。

因此,您应该将同步循环拆分为多个异步部分,以免被冻结。

例如(我减少参数以没有太多时间等待(:

async function calcX() {
let x = 0;
function iteration(i) {
x += (i * 99999);
if (++i >= 10000) return Promise.resolve(x);
return new Promise((resolve) => {
setTimeout(() => iteration(i).then(resolve), 0);
// or requestAnimationFrame
});
}
return await iteration(1);
}
const start = Date.now();
calcX()
.then(x => console.log(x, Date.now() - start), err => console.error(err));
// 4999450005000 42465
如果将每个迭代都放到事件循环中,可能会太慢。所以你可以通过批量处理它们来优化它(见@Steve的回答(

或者使用WebWorker执行繁重的同步任务

您可以将长时间运行的同步函数转换为异步函数,方法是检查是否经过了设定的时间,然后稍后返回函数(在本例中通过setTimeout实现(:

var lastBreak = Date.now()
function takeABreak() {
return new Promise(resolve=>setTimeout(resolve));
}
async function maybeTakeABreak() {
if (Date.now() - 17 > lastBreak) {
lastBreak = Date.now();
await takeABreak();
}
}
async function myLongLoop() {
let x = 0;
for (let i = 1; i < 100000000000000; i++) {
await maybeTakeABreak();
x += (i * 99999);
if (!(i%1000000)) {
console.log(i);
// alternatively you could run `await takeABreak();` here
}
}
return x;
}
myLongLoop().then(x=>console.log(x));

最新更新