【问题标题】:Trouble with node asynchronous GET request using promises使用 Promise 的节点异步 GET 请求出现问题
【发布时间】:2016-02-14 11:01:48
【问题描述】:

我对编程非常陌生(3 个月),并且在节点如何处理异步函数方面遇到了麻烦(我认为)。

我有一个带有方法“addMenu”的 Merchant 类对象,该方法从外部 API 发出对菜单的 GET 请求,然后通过将 Merchant.data.menu 对象(默认为 null)设置为我们刚得到的新菜单。

有问题的代码:

this.addMenu = function(currentMerchant) {
  var id = currentMerchant.id;

  function  getMenu(id) {
    var deferred = Q.defer();
    var url = 'https://api.delivery.com/merchant/'+id+'/menu?client_id=xyz';

    request.get(url, function(error, response, body) {
      if(error) {
        console.log("Something went wrong with menu GET request: Status Code: " + response.statusCode);
        deferred.reject(new Error(error));
      } else if(!error && response.statusCode == 200) {
        menuObj = JSON.parse(body);
        deferred.resolve(menuObj);
      }        
    });

    return deferred.promise;
  };

  this.data.menu  = getMenu(id).then(function(currentMenu) {
    return currentMenu;
  });

  console.log(this.data.menu);
};

当我登录 (this.data.menu) 时,我得到“{ state: 'pending' }”。我可以做 setTimeout 并让事情正常工作,但这不会违背承诺的全部目的吗?几天来,我一直被这个普遍的问题所困扰——一直在研究回调、延迟、承诺等来解决它,但我认为我可能错过了一些更基本的想法。

谢谢!

编辑添加

毕竟我意识到我的问题的真正症结在于无法从回调/承诺内部访问 this.data.menu 这导致我做各种奇怪的事情并试图将它们返回到这。变量等。

只需阅读“var that = this;”访问类范围的技巧,这使我所有的回调和承诺尝试都可以正常工作,并且在我的脑海中变得更有意义。而且我现在知道了更多关于我曾经打算作为附带好处的承诺。感谢大家的帮助!

【问题讨论】:

  • Promise 不会神奇地使异步代码同步。它们只能简化我们对异步的处理。

标签: javascript node.js asynchronous q npm-request


【解决方案1】:

then 方法的返回仍然是一个承诺,因此不会被实现。起初,这是一个很难理解的范例。 (玩过传送门吗?:))

我想你想做这样的事情

getMenu(id).then(function(currentMenu) {
    this.data.menu  = currentMenu;
});

其中的关键部分是你在 promise 实现时调用的函数中进行赋值。

除此之外的任何代码都不能保证在承诺返回后运行(这就是您获得该控制台输出的原因)

【讨论】:

  • 看到这很有意义,这也是我最初设置它的方式。但我无法从 .then 函数回调中访问“this.data.menu”。我想这就是我卡住的地方。如果我尝试将它临时分配给 addMenu 方法中的一个变量,然后将其分配给 'this.data.menu,它只有在我添加延迟时才能成功地将其粘贴在那里,所以我们回到第一方......顺便说一句,感谢您的帮助!
  • 看来您现在正在努力解决的是回调中 this 的范围。有很多帖子可以比我更好地解释这一点。这是一个非常普遍的问题,有些人主张永远不要使用它,而其他人则不同意。由你决定。这是一个示例帖子weblogs.asp.net/dwahlin/…
  • 感谢 ScottG,这正是我的问题...将研究有关“此”用法的理论
【解决方案2】:

您还可以使用 bluebird 来承诺请求并执行以下操作:

var Promise = require('bluebird');

var getRequest = Promise.promisify(require('http').get);

this.addMenu = function(currentMerchant) {
  var id = currentMerchant.id;

  function  getMenu(id) {
    var deferred = Q.defer();
    var url = 'https://api.delivery.com/merchant/'+id+'/menu?client_id=xyz';

    return getRequest(url);
  }

  this.data.menu  = getMenu(id)
                      .then(function(response) {
                        return JSON.parse(response.body);
                      })
                      .catch(function (err){
                        console.log("Something went wrong with menu GET request: " + err);
                      });

  console.log(this.data.menu);
};

【讨论】:

  • 是的,所以放弃 Q 并使用允许您承诺回调的库。他的问题不在于缺乏对 Promise 的理解,而是将 Promise 与回调混为一谈。
  • 否; OP 已经正确设置了使用 Promise 的请求;问题是他们错误地使用了返回值。切换库不会有什么不同。看来您的代码也有同样的困惑。
  • 感谢 user2640213 的建议,现在就来玩弄蓝鸟。我可以看到 GET 请求的承诺可能如何回避我的问题,但我认为数学可能是正确的,我在概念上错过了更大的难题
猜你喜欢
  • 2016-04-25
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-25
  • 2016-06-01
  • 1970-01-01
相关资源
最近更新 更多