【问题标题】:How to wait all Promises to resolve in ExpressJS?如何在 ExpressJS 中等待所有 Promises 解决?
【发布时间】:2019-01-12 21:27:11
【问题描述】:

背景:

我在 ExpressJS 中有一个简单的 REST API,它允许将多个页面分阶段处理在一起。页码是动态的。

问题:

由于性能限制,我想在获取多个网页时实现异步承诺,等待所有网页完成下载,用我想要的格式对其进行表述,然后返回输出。

在我在线研究了所有关于 Promise 和 async 的内容之后(因为我对这个 async 主题还很陌生),他们中的大多数人告诉我使用Promise.all但我就是无法做到以某种方式工作。

导航到GET /xxx时的当前输出

{
    username: xxx
    parsedHTML: []
}

目标输出:

{
    username: xxx
    parsedHTML: [
        "BUNCH OF ANALYSED HTML",
        "BUNCH OF ANALYSED HTML",
        "BUNCH OF ANALYSED HTML",
        ...
    ]
}

代码

const express = require("express");
const http = require("http");
const fetch = require('node-fetch');

const app = express();

app.get("/:username", (req, res)=>{
    const username = req.params.username;
    let page = 3; //Will be obtained dynamically. But for now, I'll put a constant here
    res.json({
        username: username,
        parsedHTML: getParsedHTML(username, page),
    });
    console.log("Page sent")
})

function getParsedHTML(username, page) {

    let promises = [];
    let analyses = [];

    for (var i = 1; i < (page + 1); i++) {
        promises.push(fetch(`https://example.com/profile/${username}/?page=${i}`)
                .then((c) => c.text()));
        // console.log(`Added promise`)
    }
    Promise.all(promises).then(()=>{
        for (let i = 0; i < promises.length; i++) {
            let promise = promises[i];
           analyses.push(analyse(promise));

        }
    })
    return analyses;
}

function analyse(html){
    // Some synchronous analyse stuff here
    // Right now it do nothing
    return html;
}

app.listen(3000, () => console.log('API listening on port ' + 3000 + '!'))

任何帮助将不胜感激。非常感谢。

【问题讨论】:

    标签: javascript node.js express promise


    【解决方案1】:

    您在promises 上正确调用了Promise.all,但getParsedHTML 函数没有等待Promise.all 调用在返回之前解决。因此,您的res.json 正在立即同步运行,而返回的analyses 是一个空数组。

    改为返回Promise.all 调用,并确保响应(来自Promise.all 调用)而不是Promises:

    return Promise.all(promises).then((responses)=>{
      for (let i = 0; i < responses.length; i++) {
        let response = responses[i];
        analyses.push(analyse(response));
      }
    }).then(() => analyses);
    

    但是您可以通过映射生成的响应数组来显着清理您的代码:

    function getParsedHTML(username, page) {
      let promises = [];
      for (var i = 1; i < (page + 1); i++) {
        promises.push(fetch(`https://example.com/profile/${username}/?page=${i}`)
                      .then((c) => c.text()));
      }
      return Promise.all(promises)
        .then((responses) => responses.map(analyse));
    }
    

    还要确保在发送res.json之前等待getParsedHTML等待返回的Promises解决:

    app.get("/:username", (req, res)=>{
      const username = req.params.username;
      let page = 3; //Will be obtained dynamically. But for now, I'll put a constant here
      getParsedHTML(username, page)
        .then((parsedHTML) => {
          res.json({
            username,
            parsedHTML
          });
          console.log("Page sent")
        });
    })
    

    【讨论】:

    • 您的第一个代码块正在调用analyse(promise)。那肯定看起来不太对劲。您希望在 Promise.all() 之后处理已解决的结果,而不是仍然使用承诺。如果你确实处理了这些承诺,你必须在它们上使用.then() 才能得到结果。可能需要Promise.all(promises).then(results =&gt; { /* use results array here */})
    • 非常感谢!!这个问题已经困扰了我几个小时:(
    • 您可以通过在主循环中链接 analyse 来进一步清理代码 - 甚至可以使用单行代码 return Promise.all(Array.from({length:page},(_, i)=&gt;i+1).map(i =&gt; fetch(example.com/profile/${username}/?page=${i} ).then((c) =&gt; c.text()).then(analysise)); - 很干净:p
    猜你喜欢
    • 2018-04-01
    • 2021-05-19
    • 1970-01-01
    • 2022-01-17
    • 2014-03-12
    • 2023-03-19
    • 1970-01-01
    • 2017-05-07
    相关资源
    最近更新 更多