Meteor - 使用Meteor.wrapAsync()包装NPM

时间:2014-11-24 16:11:38

标签: javascript meteor

我正在尝试使用Meteor.wrapAsync包装超级NPM,一切正常,直到下面代码的最后一行,这会导致我的meteor应用程序崩溃。

var superagent = Meteor.npmRequire('superagent');

// Example of how superagent works
superagent.get('http://127.0.0.1:8080/json/', function(result){
    console.log(result); // Works, shows the result
});

// This appears to work too
var agentAsync = Meteor.wrapAsync(superagent.get);

// This crashes app
agentAsync('http://127.0.0.1:8080/json/');

我也尝试过将一个上下文传递给wrapAsync(),但没有区别:

var agentAsync = Meteor.wrapAsync(superagent.get, superagent);

这是控制台输出:

W20141124-17:31:32.094(0)? (STDERR)           
W20141124-17:31:32.136(0)? (STDERR) /home/ciwolsey/.meteor/packages/meteor-tool/.1.0.35.1bjny7b++os.linux.x86_64+web.browser+web.cordova/meteor-tool-os.linux.x86_64/dev_bundle/lib/node_modules/fibers/future.js:206
W20141124-17:31:32.136(0)? (STDERR)                         throw(ex);
W20141124-17:31:32.137(0)? (STDERR)                               ^
W20141124-17:31:32.137(0)? (STDERR) [object Object]
W20141124-17:31:32.137(0)? (STDERR)     at Object.Future.wait (/home/ciwolsey/.meteor/packages/meteor-tool/.1.0.35.1bjny7b++os.linux.x86_64+web.browser+web.cordova/meteor-tool-os.linux.x86_64/dev_bundle/lib/node_modules/fibers/future.js:326:15)
W20141124-17:31:32.137(0)? (STDERR)     at packages/meteor/helpers.js:118
W20141124-17:31:32.137(0)? (STDERR)     at app/server/main.js:5:1
W20141124-17:31:32.137(0)? (STDERR)     at app/server/main.js:8:3
W20141124-17:31:32.137(0)? (STDERR)     at /home/ciwolsey/projects/hello/.meteor/local/build/programs/server/boot.js:168:10
W20141124-17:31:32.138(0)? (STDERR)     at Array.forEach (native)
W20141124-17:31:32.138(0)? (STDERR)     at Function._.each._.forEach (/home/ciwolsey/.meteor/packages/meteor-tool/.1.0.35.1bjny7b++os.linux.x86_64+web.browser+web.cordova/meteor-tool-os.linux.x86_64/dev_bundle/lib/node_modules/underscore/underscore.js:79:11)
W20141124-17:31:32.138(0)? (STDERR)     at /home/ciwolsey/projects/hello/.meteor/local/build/programs/server/boot.js:82:5
=> Exited with code: 8

4 个答案:

答案 0 :(得分:0)

Meteor.wrapAsync接受第二个参数,它是应该调用包装函数的上下文(保留this正确值)。

请尝试使用此语法:

var agentAsync = Meteor.wrapAsync(superagent.get, superagent);

如果您没有通过正确的上下文,则通话会使您的应用崩溃,因为它无法提取this属性,因为它通常会在您拨打{{1}时执行此操作直接。

答案 1 :(得分:0)

您是否尝试过使用Future? 这是一个例子

Meteor.methods({
  syncMethod: function() {
    // load Future
    Future = Npm.require('fibers/future');
    var theFuture = new Future();

    // call the function and store its result
    TheAsyncFuncWeWantItToWait("foo", function (error,results){
      if(error){
        theFuture.throw(error);
      }else{
        theFuture.return(results);
      }
    });

    return theFuture.wait();
  }
});

答案 2 :(得分:0)

以下是Meteor.wrapAsync的来源和superget.get

的来源

Meteor.wrapAsync基本上是Meteor.bindEnviroment周围的薄包装。它提供了一个等待Fiber的绑定函数。

superget.get最终尝试使用Request.prototype.callback

调用传递给它的回调函数

这里有趣的是Meteor.bindEnvironment接受Fibers.resolver函数(它带有两个参数),并将其包含在一个带无参数的函数中

Request.prototype.callback尝试查看fn.length以查看是否应该使用(err, res)调用它或使用emit发送错误时......后者会执行后者..

为了使这项工作,我们需要短路Request.prototype.callback并让它认为没有参数的函数可以调用为fn(err, res)

superget.Request.prototype.callback = function(err, res){
  var fn = this._callback;
  if (2 == fn.length || 0 == fn.length) return fn(err, res);
  if (err) return this.emit('error', err);
  fn(res);
};

或者,您可以编写自己的Meteor.wrapAsync,它提供具有正确函数长度的回调。例如:

function wrapAsync(fn, context) {
  //XXX Shortened version of wrapAsync. Only works on server, doesn't allow for callback to be passed.
  return function (/* arguments */) {
    var self = context || this;
    var newArgs = _.toArray(arguments);
    var fut = new Future();
    var callback = Meteor.bindEnvironment(fut.resolver());
    newArgs.push(function(err, res){
      return callback.apply(this, arguments);
    });
    fn.apply(self, newArgs);
    return fut.wait()
  };
}

答案 3 :(得分:0)

我知道这是一个老问题,但我没有在这里看到明确的答案所以我想分享对我有用的东西。

const request = superagent
  .post(`${basePath}/api/xxx`)
  .set('Content-Type', 'application/json')
  .send({ fileReference });
const response = Meteor.wrapAsync(request.end, request)();

由于request.end()是需要回调的函数,因此您希望将其传递给Meteor.wrapAsync。并且您必须将回调绑定到原始请求,否则它将在全局上下文中运行(但它需要在原始请求的上下文中运行)。

希望这有助于其他人!