如何等待所有Promises在ExpressJS中解决?

时间:2018-08-05 22:54:03

标签: javascript node.js express promise

背景:

我在ExpressJS中有一个简单的REST API,可以将多个页面分阶段放置。页码是动态的。

问题:

由于性能的限制,我想在获取多个网页时实现异步承诺,等待所有网页下载完毕,以所需的格式设置它们的短语,然后返回输出。

在我研究了有关诺言和异步的所有内容之后(因为我仍然是异步主题的新手),他们中的大多数告诉我使用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 + '!'))

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

1 个答案:

答案 0 :(得分:3)

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

取而代之的是返回Promise.all调用,并确保analyze响应(来自Promise.all的调用)而不是Promise:

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

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

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