【问题标题】:Meteor with Promises流星与承诺
【发布时间】:2015-08-02 04:56:31
【问题描述】:

我一直在尝试养成使用 Promise 的习惯,但在 Meteor 上下文中尝试在服务器端代码中使用 Promise 时遇到了问题。这就是问题所在:

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
    p = function(){
      return new Promise(function(res,rej) {
        res("asd");
      });
    };
    p().then(function(asd){
      console.log("asd is " + asd);
      return "zxc"
    }).then(Meteor.bindEnvironment(function(zxc){
      console.log("zxc is " + zxc);
      return "qwe"
    })).then(function(qwe){
      console.log("qwe is " + qwe);
    });
  });
}

mvrx:bluebird 包已安装

代码也可以在GitHub获得

预期输出:

asd is asd         
zxc is zxc
qwe is qwe

实际输出:

asd is asd         
zxc is zxc
qwe is undefined

删除 Meteor.bindEnvironment 包装器可以解决问题,但我需要它才能在回调中使用集合

那么我在这里缺少什么?是不能以这种方式使用 Promises + Meteor 还是有错误?

我实际上想要完成的是具有重要部分结果但需要同步结束的并行管道。像这样。

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup


    promises = [];

     step1 = function(input){
        return new Promise(function(res, rej){
          console.log(input + ":Step 1");
          res(input);
        });
      };
      step2 = function(input){
        return new Promise(function(res, rej){
          console.log(input + ":Step 2");
          res(input);
        });
      };
      step3 = function(input){
        return new Promise(function(res, rej){
          console.log(input + ":Step 3");
          res(input);
        });
      };
      slowIO = function(input){
        var inp = input;
        return new Promise( function(res,rej){
          setTimeout(function(){
            console.log(inp + ":SlowIO");
            res(inp);
          },Math.random()*20000);
        });
      };
      end = function(input){
        return new Promise(function(res,rej){
          console.log(input + ": done, commiting to database");
          res()
        });
      };

    for (var i = 0; i < 100; ++i) {
      promises.push(step1("pipeline-" + i).then(step2).then(slowIO).then(step3).then(end));
    };

    Promise.all(promises).then(function(){
      console.log("All complete")
    });



  });
}

【问题讨论】:

  • 您可以使用Promise.promisify 承诺bindEnvironment,因为它是错误的,请查看文档

标签: javascript meteor promise bluebird


【解决方案1】:

(更新:I've logged an issue on github to see if it can be resolved.

以这种方式使用Meteor.bindEnvironment 时似乎存在问题。

If it's called from outside a Fiber it won't return it's value. 请注意Fiber(runWithEnvironment).run()之前缺少的return

目前一个简单的解决方案是返回 Promise 而不是结果:

// when passed as a callback to `Promise#then`
//  allows it to resolve asynchronously
var asyncThen = function(fn){
  return function(arg){
    return new Promise(function(resolve, reject){
      fn(arg, resolve, reject);
    })
  };
};

Promise.resolve("asd").then(function(asd){
  console.log("asd is " + asd);
  return "zxc"
}).then(
  asyncThen(
    Meteor.bindEnvironment(function(zxc, resolve, reject){
      console.log("zxc is", zxc);
      resolve("qwe");
    })
  )
).then(function(qwe){
  console.log("qwe is " + qwe);
});

【讨论】:

  • 看起来不返回值是设计使然:请参阅packages/meteor.js:1003 我还尝试通过简单地在其中放置一个返回来修补它,这会在编译时导致错误。按照您建议的方式执行此操作对我不起作用,因为在调用 bindEnvironment 时我已经在光纤之外,因此在尝试绑定时出现“流星代码必须始终在光纤内运行。...”错误。
  • 嗯.. 看起来是这样;我已经更新了我对可行的答案
  • workFn 你的意思是使用 zxc 而不是 argZxc 对吗?因为那行得通。
  • @RauBan 我再次对其进行了调整,使其更清洁/可重复使用
  • 谢谢,这真是太好了。我添加了var fn = Meteor.bindEnvironment(fn); 以进一步减少链接时的混乱。
【解决方案2】:

promise 只是一种以同步方式编写异步代码的方法。 如果这就是你的全部,为什么不使用Meteor.wrapAsync()?在你的情况下,你有zxc骑牛仔在它自己的纤维&谁知道它什么时候回来。 Bluebird 在客户端非常棒且速度超快,但我认为使用 Meteor 提供的代码更简洁:

//*UNTESTED*//
asd = function() { return 'foo';};
asdSync = Meteor.wrapAsync(asd);
asdResult = asdSync();

qwe = function(input) {return input.reverse()};
qweSync = Meteor.wrapAsync(qwe);
qweResult = qweSync(asdResult); //should return 'oof'

【讨论】:

    猜你喜欢
    • 2017-01-18
    • 2017-05-12
    • 2017-02-21
    • 2016-02-10
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-09
    相关资源
    最近更新 更多