带有 API 和数据库查询的 Node.js Promise Chain

Posted

技术标签:

【中文标题】带有 API 和数据库查询的 Node.js Promise Chain【英文标题】:Node.js Promise Chain with API and database query 【发布时间】: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 循环的两个调用吗? 【参考方案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() 应该是第一次调用我自己的数据库,之后我仍然需要另一个调用我的数据库

以上是关于带有 API 和数据库查询的 Node.js Promise Chain的主要内容,如果未能解决你的问题,请参考以下文章

带有mysql查询的异步函数不会返回查询结果node.js

如何在 Node.js REST API 中处理非传统查询

带有 Node JS 和 Sails JS 的 Facebook Graph API

如何在 Node.js 中使用带有 API 网关的 AWS Lambda 发送二进制响应? [复制]

带有承诺的 MongoDB 查询不执行 if 语句(MongoDB node.js 驱动程序)

带有查询字符串参数的node.js http'get'请求