向 Promise.all 添加计时器,映射

Posted

技术标签:

【中文标题】向 Promise.all 添加计时器,映射【英文标题】:Add timer to Promise.all, map 【发布时间】:2018-06-14 02:33:03 【问题描述】:

我想在下面的 get 请求之间添加一些超时。我的意思是,流程应该是这样的:timeout, https://example.com/example1, timeout, https://example.com/example2, timeout, https://example.com/example3, timeout 等等(或者没有第一次超时,无论如何)。

以下功能正常工作:

function promiseGetInformationFromMultipleUrls(parts) 
    return Promise.all(parts.map(part => 
      return request(
            'url': `https://example.com/$part`,
            'json': true
        ).then(partData =>  console.log("Part data was fetched: " + part); return partData.result;)
          .catch(err => console.error("Error during fetching data from part: " + part + ", error code: " + err.statusCode););
    ));

parts 在哪里 -> example1, example2, example3....

我正在尝试通过添加计时器来做到这一点:

const timer = ms => new Promise( res => setTimeout(res, ms));

并使用它:

function promiseGetInformationFromMultipleUrls(parts) 
    return Promise.all(parts.map(part => 
    console.log("wait 1 seconds");
    timer(1000).then(_=>console.log("done"));
      return request(
            'url': `https://example.com/$part`,
            'json': true
        ).then(partData =>  console.log("Part data was fetched: " + part); return partData.result;)
          .catch(err => console.error("Error during fetching data from part: " + part + ", error code: " + err.statusCode););
    ));

但这是错误的流程 -> timeout, timeout, timeout,..., get request1, get request 2, get request 3.

【问题讨论】:

“超时”是指“延迟”吗? 确实如此。超时、延迟或休眠。 Promise.all 是错误的方法。它会立即触发所有内容。你可以使用 reduce Promise 数组或使用 await。 是的,它是一次性的。嗯,谢谢,我试试改成promise.reduce。 Resolve a chain of promises with timeouts. Promise.all的可能重复 【参考方案1】:

您可以将其简化为 Promise 链:

function promiseGetInformationFromMultipleUrls(parts) 
 return parts.reduce((chain, part) =>
  chain.then((result) =>
    timer(1000).then(() => 
      request(/*...*/).then(res => 
        result.concat(res)
      )
    )
  ),
  Promise.resolve([])
);

但是那很丑,所以你可以使用 async / await 代替:

 async function promiseGetInformationFromMultipleUrls(parts)
   const result = [];
   for(const part of parts)
     await timer(1000);
     result.push(await request(/*...*/));
  
  return result;

【讨论】:

对我来说,最好的解决方案不会改变对异步进程部件功能的承诺。我的问题的承诺只是所有脚本中的 sn-p。 在第一个提案中 - parts.reduce((chain, part) => 零件在哪里?我想将每一行添加到 url,但没有部分。 @profiler 我不明白你。你能改写一下吗? 对不起。关于第一个解决方案 - 承诺链。没有什么“部分”,只有部分。我应该在哪里切片并在请求部分使用? @profiler part 是您的 parts 数组的一个元素。【参考方案2】:

以下应该有效:

const Fail = function(reason)this.reason=reason;;
const isFail = x=>(x&&x.constructor)===Fail;
const timedoutPromise = time => promise => 
  Promise.race([
    promise,
    new Promise(
      (resolve,reject)=>
        setTimeout(
          x=>reject("timed out"),
          time
        )
    )
  ]);

utls = [];//array of urls
in5Seconds = timedoutPromise(5000);
Promise.all(
  urls.map(
    url=>
      in5Seconds(makeRequest(url))
      .catch(e=>new Fail([e,url]))//failed, add Fail type object
  )
)
.then(
  results=>
    const successes = results.filter(x=!isFail(x));
    const failed = results.filter(isFail);
    const timedOut = failed.filter(([e])=>e==="timed out");
  
)

【讨论】:

以上是关于向 Promise.all 添加计时器,映射的主要内容,如果未能解决你的问题,请参考以下文章

向文本块 WPF 添加倒数计时器

向 iOS 应用程序添加正在运行的计数显示计时器,例如时钟秒表?

使用 promises 索引映射 Promise.all 输出

按秒倒数计时器

带有嵌套地图的 Promise.all .. 第一张地图仅适用于其他人在猫鼬中返回空对象

向使用 GDI+ 绘制的图像添加文本