2014-11-24 87 views
2

我想用Meteor.wrapAsync包装superagent NPM,一切工作正常,直到下面的代码的最后一行,这导致我的流星应用程序崩溃。流星 - 用Meteor.wrapAsync包装NPMs()

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 

回答

0

这里的源Meteor.wrapAsync和源极到superget.get

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

superget.get最终试图调用传递给它的回调函数与Request.prototype.callback

其中有趣的是,Meteor.bindEnvironmentFibers.resolver功能(需要两个参数),并把它封装在采用没有的功能参数

所以当Request.prototype.callback尝试一下​​,看它是否应该(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() 
    }; 
} 
+0

在流星github上关于这个https://github.com/meteor/meteor/issues/3176 – 2014-11-25 07:21:17

+0

打开了一个问题很好的解释,谢谢你做出这样的努力,并提交它作为一个问题;) – ciwolsey 2014-11-26 00:40:28

0

Meteor.wrapAsync需要第二个参数这是应该调用包装函数的上下文(以保留this正确的值)。

尝试使用此语法来代替:

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

如果没有传递正确的情况下,呼叫会崩溃您的应用程序,因为它不能获取this属性,它应该通常做的时候你直接拨打superagent.get

+0

我已经试过了,只是再试一次。我仍然遇到崩溃。 – ciwolsey 2014-11-24 17:04:30

+0

请详细说明您收到的错误消息吗? – saimeunt 2014-11-24 17:24:03

+0

我得到的错误:https://gist.github.com/ciwolsey/5ac57ce27eeeea34d23c – ciwolsey 2014-11-24 17:34:01

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(); 
    } 
}); 
+0

我认为这将工作,因为它工作时,我手动使用光纤,但我只是好奇,为什么没有流星包装方法工作。 – ciwolsey 2014-11-24 18:40:11

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什么。您必须将回调绑定到原始请求,否则它会在全局上下文中运行(但它需要在原始请求的上下文中运行)。

希望这可以帮助别人!