在Promise.all中解析时将Promise结果流式传输到客户端

时间:2019-01-09 23:26:18

标签: node.js promise stream

在Node中,我正在使用bluebird的Promise.all异步执行Promises。我不想等待所有Promises解决,然后再将结果发送回客户端。相反,我希望在解决每个Promise时立即流式传输结果。这可能吗?我的研究表明并非如此,但我认为值得将其推广到社区。

以下是代码(不尝试实现流式传输):

async bulkExecution(req, res) {
    try {
        const { assets } = req.body;

        let thePromises = _.map(assets, (asset) => {
            return onePromise(asset);
        });

        // I want to stream each Promise result to client as it resolves
        let results = await Promise.all(thePromises);

        return res.status(200).send(results);
    } catch (err) {
        return res.status(500).send(err);
    }
}

1 个答案:

答案 0 :(得分:0)

我认为您必须遍历所有的Promise,并对每个Promise做一个.then(),写一个部分响应,然后在所有Promise都完成后关闭响应。这样的事情应该起作用。响应的顺序可能与promise数组的顺序不同。例如,下面的示例将首先返回第二个Promise。

let res = {
  write: (data) => {console.log(data)},
  end: () => {}
};

let promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 500);
});

let promise2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

let promises = [promise1, promise2];

let count = 0;
promises.forEach((promise) => {
  promise.then((data) => {
    res.write(data);
    count++;
    if (count >= promises.length){
        res.end();
    }
  })
})

修改为以JSON格式编写。

let res = {
  write: (data) => {
    console.log(data)
  },
  end: () => {}
};

let promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve({foo:"bar"});
  }, 500);
});

let promise2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve({bar:"foo"});
  }, 300);
});

let promises = [promise1, promise2];

let count = 0;

res.write("[");
promises.forEach((promise) => {
  promise.then((data) => {
    res.write(JSON.stringify(data));
    count++;
    if (count >= promises.length) {
      res.write("]");
      res.end();
    } else {
      res.write(",");
    }
  })
})

像这样的流JSON并不常见,但是可以用来减少服务器使用的内存量。这是因为您无需在发送响应之前在内存中创建完整响应。客户端仍然需要足够的内存才能将整个对象读入内存。