2014-11-24 89 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什麼。您必須將回調綁定到原始請求,否則它會在全局上下文中運行(但它需要在原始請求的上下文中運行)。

希望這可以幫助別人!