【问题标题】:Meteor - Wrapping NPMs with Meteor.wrapAsync()Meteor - 使用 Meteor.wrapAsync() 包装 NPM
【发布时间】:2017-11-22 08:34:54
【问题描述】:

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

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

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

    这是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()
      };
    }
    

    【讨论】:

    【解决方案2】:

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

    尝试改用这种语法:

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

    如果您没有传递正确的上下文,该调用将使您的应用崩溃,因为它无法像您直接调用 superagent.get 时通常那样获取 this 属性。

    【讨论】:

    • 我已经试过了,只是又试了一次。我仍然遇到崩溃。
    【解决方案3】:

    您是否尝试过使用 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();
      }
    });
    

    【讨论】:

    • 我认为这会像我手动使用纤维时一样有效,但我只是好奇为什么没有一种流星包裹方法有效。
    【解决方案4】:

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

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

    希望这对其他人有帮助!

    【讨论】:

      猜你喜欢
      • 2016-03-28
      • 2023-03-16
      • 2023-03-03
      • 2015-01-22
      • 2017-04-13
      • 2013-03-13
      • 2018-05-26
      • 1970-01-01
      • 2019-10-21
      相关资源
      最近更新 更多