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

JavaScript ES6承诺循环

JavaScript ES6承诺循环

守候你守候我 2019-07-16 16:50:34
JavaScript ES6承诺循环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任务很简单:确保每个承诺只在另一个承诺之后运行(.then()).因为某种原因,我找不到办法去做这件事。我试过发电机功能(yield),尝试了返回承诺的简单函数,但在一天结束时,它总是归结为相同的问题:循环是同步的。.带着异步我只想用async.series().你怎么解决这个问题?
查看完整描述

3 回答

?
慕田峪9158850

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

正如您在问题中所暗示的,您的代码同步地创建所有承诺。相反,应该只在前一个解析时创建它们。

第二,每一个承诺new Promise需要通过调用resolve(或reject)。这应该在计时器过期时进行。会触发任何then你就可以收回你的承诺了。而这样的then回调(或await)是执行链所必需的。

有了这些成分,有几种方法可以执行这个异步链接:

  1. 带着for循环,以立即解决承诺开始。

  2. 带着Array#reduce首先是一个立竿见影的承诺

  3. 具有将自身传递为分辨率回调的函数。

  4. 与ECMAScript2017async / await句法

  5. 与提议的ECMAScript 2020for await...of句法

请参阅下面每个选项的代码段和注释。

1.与for

你,你们能,会,可以for循环,但您必须确保它不执行new Promise同步。相反,您创建一个初始的立即解决承诺,然后链接新的承诺,就像前面的承诺一样:

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

2.与reduce

这只是对以前策略的一种更有功能的方法。创建一个与要执行的链长度相同的数组,并从立即解析承诺开始

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

这可能更有用在承诺中使用数据的数组。

3.函数本身作为分辨率回调。

这里我们创建一个函数并立即调用它。它同步地创建了第一个承诺。当它解析时,将再次调用该函数:

(function loop(i) {
    if (i < 10) new Promise((resolve, reject) => {
        setTimeout( () => {
            console.log(i);
            resolve();
        }, Math.random() * 1000);
    }).then(loop.bind(null, i+1));})(0);

这将创建一个名为loop,在代码的末尾,您可以看到它被立即用参数0调用。这是柜台,i争论。该函数将创建一个新的承诺,如果计数器仍然低于10,否则链接停止。

打电话给resolve()将触发then回调,这将再次调用该函数。loop.bind(null, i+1)只是另一种说法_ => loop(i+1).

4.与async/await

现代JS发动机支持此语法:

(async function loop() {
    for (let i = 0; i < 10; i++) {
        await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
        console.log(i);
    }})();

它看起来可能很奇怪,因为它似乎就像new Promise()调用是同步执行的,但实际上async功能回报当它执行第一个await..每次等待的承诺解决后,函数的运行上下文都会被恢复,并在await,直到遇到下一个,直到循环结束。

由于基于超时返回承诺可能是一件常见的事情,您可以创建一个单独的函数来生成这样的承诺。这叫做亲化函数,在这种情况下setTimeout..它可以提高代码的可读性:

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);
    }})();

5.与for await...of

甚至最近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);})();



查看完整回答
反对 回复 2019-07-16
  • 3 回答
  • 0 关注
  • 482 浏览
慕课专栏
更多

添加回答

举报

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