当前位置: 首页 > 知识库问答 >
问题:

JavaScript ES6promise循环[重复]

黄修永
2023-03-14
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之后运行(. so())。

由于某种原因,我找不到一个方法来做这件事。

我尝试了生成器函数yield),尝试了返回promise的简单函数,但最终都归结为同一个问题:循环是同步的。

对于async,我只需使用async.series()

你怎么解决?

共有3个答案

唐钊
2023-03-14

基于trincot的出色回答,我写了一个可重用的函数,它接受一个处理程序来运行数组中的每个项。函数本身返回一个promise,允许您等待循环完成,您传递的处理程序函数也可以返回一个promise。

我花了一些时间才把它弄对,但我相信下面的代码在很多promise循环的情况下都是可用的。

复制粘贴就绪代码:

// SEE https://stackoverflow.com/a/46295049/286685
const loop = (arr, fn, busy, err, i=0) => {
  const body = (ok,er) => {
    try {const r = fn(arr[i], i, arr); r && r.then ? r.then(ok).catch(er) : ok(r)}
    catch(e) {er(e)}
  }
  const next = (ok,er) => () => loop(arr, fn, ok, er, ++i)
  const run  = (ok,er) => i < arr.length ? new Promise(body).then(next(ok,er)).catch(er) : ok()
  return busy ? run(busy,err) : new Promise(run)
}

要使用它,请将数组作为第一个参数进行调用,将处理函数作为第二个参数进行调用。不要为第三、第四和第五个参数传递参数,它们是在内部使用的。

const loop = (arr, fn, busy, err, i=0) => {
  const body = (ok,er) => {
    try {const r = fn(arr[i], i, arr); r && r.then ? r.then(ok).catch(er) : ok(r)}
    catch(e) {er(e)}
  }
  const next = (ok,er) => () => loop(arr, fn, ok, er, ++i)
  const run  = (ok,er) => i < arr.length ? new Promise(body).then(next(ok,er)).catch(er) : ok()
  return busy ? run(busy,err) : new Promise(run)
}

const items = ['one', 'two', 'three']

loop(items, item => {
  console.info(item)
})
.then(() => console.info('Done!'))
蓬森
2023-03-14

您可以为此使用async/await。我会解释得更多,但实际上没什么。这只是一个常规的for循环,但在构建您的promise之前,我添加了wait关键字

我喜欢的是,您的promise可以解析正常值,而不是像您的代码(或此处的其他答案)所包含的那样产生副作用。这给了你塞尔达传说中的力量:一个链接到过去,你可以影响光明世界和黑暗世界中的事物——也就是说,你可以在promise的数据可用之前/之后轻松处理数据,而不必求助于深度嵌套的函数、其他笨拙的控制结构或愚蠢的IIFE。

// where DarkWorld is in the scary, unknown future
// where LightWorld is the world we saved from Ganondorf
LightWorld ... await DarkWorld

这就是它的样子。。。

async function someProcedure (n) {
  for (let i = 0; i < n; i++) {
    const t = Math.random() * 1000
    const x = await new Promise(r => setTimeout(r, t, i))
    console.log (i, x)
  }
  return 'done'
}

someProcedure(10)
  .then(console.log)
  .catch(console.error)
骆英纵
2023-03-14

正如您在问题中已经暗示的,您的代码同步创建所有promise。相反,它们只能在前一个解析时创建。

其次,使用新promise创建的每个promise都需要通过调用解析(或拒绝)来解析。这应该在计时器过期时完成。这将触发任何回调,然后您将对该promise进行回调。而这样的然后回调(或等待)是实现该链的必要条件。

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

>

使用Array#reduce以立即解析promise开始

通过一个函数传递自己作为分辨率回调

使用ECMAScript 2017的异步/等待语法

使用ECMAScript 2020的进行等待…的语法

但是让我先介绍一个非常有用的通用函数。

使用setTimeout是可以的,但是我们实际上需要一个在计时器过期时解决的promise。让我们创建这样一个函数:这称为promisify函数,在本例中,我们将promisifysetTimeout。它将提高代码的可读性,并可用于上述所有选项:

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

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

您可以使用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));
}

 类似资料:
  • 问题内容: 我正在使用Java Swing编写游戏。我想在每次循环执行时绘制一下,并在之间稍加延迟以在屏幕上创建级联效果。我相信系统中的效率例程会将调用折叠为一个调用。无论如何,所有更改都在总延迟后立即发生。是否有某种方法可以强制系统立即重新绘制,然后在循环的每次迭代中延迟? 我的代码: 问题答案: 您可以用来强制立即重绘。 编辑:再次阅读您的问题后,对我来说,您可能正在事件分发线程上执行逻辑。这

  • 我正在制作一个基于文本的冒险游戏,我需要进行一些用户输入验证 我已经为这个特定实例设置了循环,但在输入正确的输入后,我似乎无法使循环中断。 代码: 我的输出是这样的: 你的选择是敲打还是猛击。别那么粗鲁。 大满贯 你猛地撞上沉重的橡木门,沉重的铁铰链砰的一声让位了。当你凝视城堡的第一个房间时,灰尘落在你的头上。大厅大约有五十英尺长。西墙有三扇门,东墙有两扇门。空气中弥漫着霉菌、湿气和铁的味道。曾经

  • 这里的函数是,但是如果外部循环条件是

  • 我找不到我的谜题。当我加载页面时,chrome会说:localhost页面不工作,localhost重定向了你太多次。我猜这是在创造一个循环。我可能做错了一些我无法得到的事情。这是我的密码。 授权控制器 模型 Authenticate.php config/auth.php

  • 我目前有两个循环,一个获取时间戳,另一个while循环根据时间戳查找映射信息并以某种方式输出。 我的问题是我目前正在循环浏览一个文本,并希望它在第二个循环的isdo="N"时再次从头开始读取文件,但是,情况似乎并非如此。 迄今为止的代码:

  • 这是我的代码: 我的问题是如何检查分数是否在范围内,如果输入了错误的输入,如何使循环重复。当我试图运行程序并输入一个超过范围的输入时,它会转到下一个评估数字,而不是再次尝试,直到它是真的。