错误:流星代码必须始终在光纤内运行

Tar*_*len 17 meteor

我在我的应用程序中使用条带付款,我想在成功交易后在我自己的数据库中创建收据文档

我的代码:

Meteor.methods({
  makePurchase: function(tabId, token) {
    check(tabId, String);
    tab = Tabs.findOne(tabId);

    Stripe.charges.create({
      amount: tab.price,
      currency: "USD",
      card: token.id
    }, function (error, result) {
      console.log(result);
      if (error) {
        console.log('makePurchaseError: ' + error);
        return error;
      }

      Purchases.insert({
        sellerId: tab.userId,
        tabId: tab._id,
        price: tab.price
      }, function(error, result) {
        if (error) {
          console.log('InsertionError: ' + error);
          return error;
        }
      });
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

但是,此代码返回错误:

Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
Run Code Online (Sandbox Code Playgroud)

我对Fibers不熟悉,为什么会这样呢?

Tom*_*cik 29

这里的问题是你传递给的回调函数Stripe.charges.create是异步调用的(当然),所以它发生在当前的Meteor之外Fiber.

解决这个问题的一种方法是创建自己的Fiber,但最简单的方法就是用回调来包装回调Meteor.bindEnvironment,基本上就是这样

Stripe.charges.create({
  // ...
}, Meteor.bindEnvironment(function (error, result) {
  // ...
}));
Run Code Online (Sandbox Code Playgroud)

编辑

正如在另一个答案中所建议的那样,另一个可能更好的模式是使用Meteor.wrapAsync辅助方法(参见docs),它基本上允许您将任何异步方法转换为具有光纤感知功能且可以同步使用的功能.

在您的具体情况下,一个等效的解决方案是写:

let result;
try {
  result = Meteor.wrapAsync(Stripe.charges.create, Stripe.charges)({ /* ... */ });
} catch(error) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

请注意第二个参数传递给Meteor.wrapAsync.它是为了确保原件Stripe.charges.create将获得适当的this上下文,以防万一需要它.