如何从Meteor自己的回调中调用异步方法?

时间:2013-04-29 00:14:42

标签: meteor node-fibers

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

不幸的是,我仍然无法管理用户光纤或期货。

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

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

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。

我尝试将返回调用放在光纤内部,这只会让事情变得更糟:它永远不会返回用户。它确实如此,但是太晚了3秒,所以下游的一切都在拯救。

感谢您的帮助!

4 个答案:

答案 0 :(得分:5)

回答我自己的问题,希望将来可以帮助一些人。这是基于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

我希望它有所帮助!

答案 1 :(得分: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 :(得分:0)

方法调用在服务器端使用同步样式(请参阅此处的{sync call'http://docs.meteor.com/#meteor_call),这是此create用户方法运行的地方 - 您应该可以执行类似

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

答案 3 :(得分:0)

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

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