为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

天涯尽头无女友 2023-07-29 15:36:09
也许这是一个 async/await 情况,但我认为 async 主要用于 api 调用(?)你如何等待一个很长的循环完成,就像这样:let x;for (i = 1, i < 10000000000000000, i++) {  x += (i * 99999);}console.log(x);
查看完整描述

2 回答

?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

我认为 async 主要用于 api 调用(?)

有两个与该词相关的不同概念async

  • async/await函数以同步方式接收 Promises 结果的语法糖

  • 真正的异步行为 XHR api 调用、延迟执行、事件处理

async/awaitfunction 不会自动使您的函数执行异步。

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 来完成繁重的同步任务


查看完整回答
反对 回复 2023-07-29
?
森栏

TA贡献1810条经验 获得超5个赞

您可以通过检查是否已经过了设定的时间,然后稍后返回该函数,将长时间运行的同步函数转换为异步函数(在此示例中通过 实现)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));


查看完整回答
反对 回复 2023-07-29
  • 2 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信