gpt4 book ai didi

JavaScript ES6 promise for 循环

转载 作者:IT王子 更新时间:2023-10-29 02:43:35 24 4
gpt4 key购买 nike

for (let i = 0; i < 10; i++) {
const promise = new Promise((resolve, reject) => {
const timeout = Math.random() * 1000;
setTimeout(() => {
console.log(i);
}, timeout);
});

// TODO: Chain this promise to the previous one (maybe without having it running?)
}

以上将给出以下随机输出:
6
9
4
8
5
1
7
2
3
0

任务很简单:确保每个 Promise 仅在另一个 Promise 之后运行( .then() )。

由于某种原因,我找不到办法做到这一点。

我尝试了生成器函数( yield),尝试了返回 promise 的简单函数,但最终它总是归结为同样的问题: 循环是同步的 .

async我会简单地使用 async.series() .

你如何解决它?

最佳答案

正如您在问题中已经暗示的那样,您的代码会同步创建所有 promise 。相反,它们应该只在前一个解决时创建。
其次,使用 new Promise 创建的每个 promise 需要调用 resolve 来解决(或 reject )。这应该在计时器到期时完成。这将触发任何 then回调你会在那个 promise 上。还有这样的then回调(或 await )是实现链的必要条件。
有了这些成分,有几种方法可以执行这种异步链接:

  • for以立即解决的 promise 开始的循环
  • Array#reduce从立即解决的 promise 开始
  • 使用将自身作为解析回调传递的函数
  • 使用 ECMAScript2017 的 async / await syntax
  • 使用 ECMAScript2020 的 for await...of syntax

  • 但让我先介绍一个非常有用的通用函数。
    promise setTimeout使用 setTimeout很好,但我们实际上需要一个在计时器到期时解决的 promise 。所以让我们创建这样一个函数:这被称为promisifying一个函数,在这种情况下我们将promisify setTimeout .它将提高代码的可读性,并可用于上述所有选项:
    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
    请参阅以下每个选项的片段和评论。
    1.与 for您可以使用 for循环,但您必须确保它不会同步创建所有 promise 。相反,您创建一个初始的立即解决 promise ,然后在之前的 promise 解决时链接新的 promise :

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

    for (let i = 0, p = Promise.resolve(); i < 10; i++) {
    p = p.then(() => delay(Math.random() * 1000))
    .then(() => console.log(i));
    }

    所以这段代码创建了一长串 then来电。变量 p仅用于不丢失该链的跟踪,并允许循环的下一次迭代在同一链上继续。回调将在同步循环完成后开始执行。
    重要的是 then -callback 返回 delay() 的 promise 创建:这将确保异步链接。
    2.与 reduce这只是对先前策略的一种更实用的方法。您创建一个与要执行的链长度相同的数组,并从立即解决的 promise 开始:

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

    [...Array(10)].reduce( (p, _, i) =>
    p.then(() => delay(Math.random() * 1000))
    .then(() => console.log(i))
    , Promise.resolve() );

    当您实际上有一个包含要在 Promise 中使用的数据的数组时,这可能更有用。
    3. 使用一个函数将自身作为解析回调传递
    这里我们创建一个函数并立即调用它。它同步创建第一个 promise 。当它解析时,再次调用该函数:

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

    (function loop(i) {
    if (i >= 10) return; // all done
    delay(Math.random() * 1000).then(() => {
    console.log(i);
    loop(i+1);
    });
    })(0);

    这将创建一个名为 loop 的函数,并且在代码的最后,您可以看到它立即使用参数 0 调用。这是计数器和 i 参数。如果该计数器仍低于 10,该函数将创建一个新的 Promise,否则链接将停止。
    delay()解决,它将触发 then回调将再次调用该函数。
    4. 与 async/ await现代 JS 引擎 support this syntax :

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

    (async function loop() {
    for (let i = 0; i < 10; i++) {
    await delay(Math.random() * 1000);
    console.log(i);
    }
    })();

    它可能看起来很奇怪,因为 promise 似乎是同步创建的,但实际上 async函数在执行第一个 await 时返回.每次等待的 promise 解决时,函数的运行上下文都会恢复,并在 await 之后继续。 , 直到遇到下一个,所以它继续直到循环结束。
    5. 与 for await...of在 EcmaScript 2020 中, for await...of 找到了现代 JavaScript 引擎的方式。尽管在这种情况下它并没有真正减少代码,但它允许将随机区间链的定义与它的实际迭代隔离开来:

    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

    async function * randomDelays(count, max) {
    for (let i = 0; i < count; i++) yield delay(Math.random() * max).then(() => i);
    }

    (async function loop() {
    for await (let i of randomDelays(10, 1000)) console.log(i);
    })();

    关于JavaScript ES6 promise for 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40328932/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com