【问题标题】:How to call async method from Meteor own callbacks?如何从 Meteor 自己的回调中调用异步方法?
【发布时间】:2013-04-22 13:54:54
【问题描述】:

我刚刚花了几个小时阅读 SO 的答案,例如 Meteor: Calling an asynchronous function inside a Meteor.method and returning the result

不幸的是,我仍然没有设法使用光纤或期货。

我正在尝试做一些相当简单的事情(我想!)。

创建用户时,根据异步方法的结果向用户对象添加一个变量。所以想象一下,如果你会在名为 BANK 的第 3 方数据库服务器上调用我的异步方法,这可能需要几秒钟才能返回。

Accounts.onCreateUser(function(options,user){

var Fiber = Npm.require("fibers");

Fiber(function() { 
    BANK.getBalance(function(err, theBalance) {

        if (err) return console.log(err);

        _.extend(user,{
            balance: theBalance;
        });

    });
}).run();

return user;

});

所以上面发生的事情是调用了 BANK 方法,但是当它返回时,代码已经继续前进,并且永远不会调用 _.extend。

我尝试将返回调用放在 Fiber 中,这只会让事情变得更糟:它永远不会返回用户。确实不错,但已经晚了 3 秒,所以到那时下游的一切都在救助。

感谢您的帮助!

【问题讨论】:

  • 向那些不加解释地否决我的问题的人打招呼……可能是 PHP 粉丝。

标签: meteor node-fibers


【解决方案1】:

在服务器端代码上使用 this.unblock()。

来自 Meteor 1.0 文档:“允许来自该客户端的后续方法开始在新光纤中运行。在服务器上,来自给定客户端的方法一次运行一个。来自客户端的 N+1 次调用不会启动直到第 N 次调用返回。但是,您可以通过调用 this.unblock 来更改它。这将允许第 N+1 次调用开始在新的纤程中运行。"

Meteor.methods({checkTwitter: function (userId) {
 check(userId, String);
 this.unblock();
 try {
   var result = HTTP.call("GET", "http://api.twitter.com/xyz",
                       {params: {user: userId}});
  return true;
 } catch (e) {
  // Got a network error, time-out or HTTP error in the 400 or 500 range.
 return false;
 }

}});

【讨论】:

    【解决方案2】:

    非常感谢你的工作,这个解决方案更适合 Meteor 项目,因为默认安装了 Fibers 模块。 mrt add npm 也有一个方法 -> Meteor.sync 。对于任何 nodeJS 项目,都有一个基于 Fibers 的模块,它的名字是 Fibrous

    参考:https://github.com/goodeggs/fibrous

    【讨论】:

      【解决方案3】:

      回答我自己的问题,希望将来能对某些人有所帮助。这是基于 Avital Oliver 和 David Glasser 的出色建议,看看 Mike Bannister 的 meteor-async.md。你可以在这里阅读:https://gist.github.com/possibilities/3443021

      Accounts.onCreateUser(function(options,user){
          _.extend(user,{
              balance: getBalance(),
          });
        return user;
      });
      
      
      function getBalance() {
        var Future = Npm.require("fibers/future");
        var fut = new Future();
        BANK.getBalance(function(err, bal) {
          if (err) return console.log(err);
          fut.return(bal);
        });
        return fut.wait();
      }
      

      我相信有更好的方法来处理这个问题,即直接将 BANK API 包装在 npm 包本身的 Futures 中,根据这个示例(来自 Avital Oliver):https://github.com/avital/meteor-xml2js-npm-demo/blob/master/xml2js-demo.js

      希望对你有帮助!

      【讨论】:

      • 那么,如果发生错误会发生什么?当那个未来永远不会回来时会发生什么?有没有办法拒绝期货?
      • 是的,如果有人可以评论优雅的错误处理,那就太好了!现在因为你不能在将来抛出 Meteor.throw(),我必须在调用它的函数中进行错误处理......真的很丑:(
      【解决方案4】:

      方法调用在服务器端使用同步样式(请参阅此处的“同步调用”http://docs.meteor.com/#meteor_call),这是创建用户方法运行的地方 - 您应该能够执行类似的操作

      Accounts.onCreateUser(function(options, user) {
        user.balance = Meteor.call('getBankBalance', params);
        return user;
      });
      

      【讨论】:

      • 嗨 Nate,遗憾的是 call 方法对我不起作用,因为 Meteor.call('getBalance', param) 只会调用服务器 API 调用的现有实现,它是异步和需要几秒钟才能返回等。无论如何,谢谢!
      • 实际上,延伸到这一点,如果我只是调用 Meteor.call('BANK.getBalance'),它似乎可以正确处理第一个调用,并且每个后续调用都会一遍又一遍地返回相同的余额.不知道为什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      • 2018-01-23
      • 2016-07-20
      • 1970-01-01
      相关资源
      最近更新 更多