【问题标题】:Node.js Promise Chain with API and database query带有 API 和数据库查询的 Node.js Promise Chain
【发布时间】:2016-05-26 14:14:40
【问题描述】:

我对整个承诺业务很陌生,正在与他们一起尝试我的项目。
不,我需要查询一个外部 API,在响应中执行几个项目,用它们对我自己的数据库进行其他检查,当所有这些都完成后,需要自己解决整个承诺。
我还需要在标记点再次调用我的数据库并做出另一个承诺。这些是相互独立的,但“父”承诺只有在两者都解决时才会解决。
我在这里遇到了困难,可能需要一些关于将多个承诺与多个项目链接起来的一般解释。
也许我只是在这里理解了一些普遍错误的东西...... 到目前为止,这是我的代码(缩写为 ...):

'use strict';

import rp from 'request-promise';
import _ from 'lodash';

var Import = {
  init: function(user, options) {
    return new Promise((resolve, reject) => {
      rp.get("...") // call to external API
        .then((res) => {
          ...
          resolve();
        });
      ...
    });
  },
  run: function() {
    return new Promise((resolve, reject) => {
      ...

      rp.get(...) // call to external API
        .then((res) => {
          var events = JSON.parse(res).data;
          var promises = [];

          for (var i = 0; i < events.length; i++) {

            promises.push(new Promise((resolve, reject) => {
              ...

              Location.findOneAndUpdateAsync(...)
                .then((loc) => {
                  events[i].location = loc._id;
                  resolve();
                })
                .catch((err) => {
                  console.error(err);
                  reject();
                });

              // I need even another call to my database here later with another promise
            }));
          }
          return Promise.all(promises)
            .then(() => {
              console.log("all promises resolved");
              resolve(events);
            });
        })
        .catch((err) => {
          console.error(err);
          reject(err);
        });
    });
  }
};

【问题讨论】:

  • 将您的问题隐藏在代码中的 cmets 内无济于事...您还使用了典型的承诺“反模式”,即在您的循环中创建一个新的承诺已经创建了一个承诺的函数。
  • 这些本来应该是一个补充,但我要改变它
  • 首先,避免Promise constructor antipattern。你的函数已经返回了 Promise。
  • 听起来你在找Promise.all([onePromise, otherIndependentPromise]).then(whenBothAreDone)
  • @Kageetai 是您希望 inside 循环的两个调用吗?

标签: javascript node.js api promise


【解决方案1】:

您可以通过不违反Promise constructor anti-pattern 来显着简化您的代码 - 您调用的函数已经返回承诺,因此您应该利用这些承诺。

然后,用Array.prototype.map 消除for / push 循环:

var promises = events.map(function(event) {
    return Location.findOneAndUpdateAsync(...)
            .then((loc) => event.location = loc._id);
});

你说你有两组调用,但由于它们是独立的,你不妨使用另一个.map调用:

var promises2 = events.map(function(event) {
    return ...
});

然后您只需要等待所有这些并返回您的 events 对象:

return Promise.all(promises.concat(promises2)).then(() => events);

不需要所有 .catch 块 - 您应该让错误向上传播。

如果(根据您的 cmets)这两个内部调用有依赖关系,您可以试试这个:

var promises = events.map(function(event) {
    return Location.findOneAndUpdateAsync(...)
           .then((loc) => {
               event.location = loc._id;
               if (condition) {
                   return XXXOtherFunctionReturningPromise();
               }
           });
});

[然后显然消除上面的.concat调用]

【讨论】:

  • 嗯,如果第一个(我仍然必须实现)调用(我自己database) 返回一个具体的答案?
  • 可能很容易,但不是您要求的! ;-)
  • 是的,我自己的错,只是重新考虑了整个过程...... X-)
  • 我添加了一些内容,但现在重新阅读您的评论时,我不确定您的要求是什么。第一个呼叫是“循环中的第一个”,还是 rp.get() 呼叫?
  • 我的意思是我所做的 Location.findOneAndUpdateAsync() 应该是第一次调用我自己的数据库,之后我仍然需要另一个调用我的数据库
猜你喜欢
  • 2015-03-09
  • 1970-01-01
  • 1970-01-01
  • 2018-10-12
  • 2016-10-29
  • 1970-01-01
  • 2017-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多