【问题标题】:What's going on with Meteor and Fibers/bindEnvironment()?Meteor 和 Fibers/bindEnvironment() 是怎么回事?
【发布时间】:2013-11-28 11:37:38
【问题描述】:

我在使用 Fibers/Meteor.bindEnvironment() 时遇到了困难。如果集合开始为空,我尝试更新代码并将其插入到集合中。这一切都应该在启动时在服务器端运行。

function insertRecords() {
  console.log("inserting...");
  var client = Knox.createClient({
    key: apikey,
    secret: secret,
    bucket: 'profile-testing'
  });
  console.log("created client");
  client.list({ prefix: 'projects' }, function(err, data) {
    if (err) {
      console.log("Error in insertRecords");
    }

    for (var i = 0; i < data.Contents.length; i++)  {
      console.log(data.Contents[i].Key);
      if (data.Contents[i].Key.split('/').pop() == "") {
        Projects.insert({ name: data.Contents[i].Key, contents: [] });
      } else if (data.Contents[i].Key.split('.').pop() == "jpg") {
        Projects.update( { name: data.Contents[i].Key.substr(0,
                           data.Contents[i].Key.lastIndexOf('.')) },
                         { $push: {contents: data.Contents[i].Key}} );
      } else {
        console.log(data.Contents[i].Key.split('.').pop());
      }
    }      
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    if (Projects.find().count() === 0) {
      boundInsert = Meteor.bindEnvironment(insertRecords, function(err) {
        if (err) {
          console.log("error binding?");
          console.log(err);
        }
      });
      boundInsert();
    }
  });
}

我第一次写这篇文章时,我遇到了需要将回调包装在 Fiber() 块中的错误,然后在 IRC 的讨论中有人建议尝试 Meteor.bindEnvironment(),因为那应该将它放在 Fiber 中.那没有用(我看到的唯一输出是inserting...,这意味着 bindEnvironment() 没有抛出错误,但它也没有运行块内的任何代码)。然后我到了这个。我现在的错误是:Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.

我是 Node 新手,并不完全理解 Fibers 的概念。我的理解是,它们类似于 C/C++ 中的线程/每种语言中的线程,但我不明白扩展到我的服务器端代码的含义是什么/为什么我的代码在尝试插入时抛出错误一个集合。谁能给我解释一下?

谢谢。

【问题讨论】:

    标签: node.js mongodb meteor node-fibers


    【解决方案1】:

    您对 bindEnvironment 的使用稍有错误。因为它被使用的地方已经在纤程中,而来自 Knox 客户端的回调不再在纤程中。

    bindEnvironment 有两个用例(我能想到,可能还有更多!):

    • 您有一个必须更改的全局变量,但您不希望它影响其他用户的会话

    • 您正在使用第三方 api/npm 模块管理回调(看起来确实如此)

    Meteor.bindEnvironment 创建一个新的 Fiber 并将当前 Fiber 的变量和环境复制到新的 Fiber 中。当你使用 nom 模块的方法回调时,你需要这样做。

    幸运的是,有一个替代方案可以处理等待您的回调并将回调绑定在名为 Meteor.wrapAsync 的纤程中。

    所以你可以这样做:

    你的启动函数已经有一个纤程并且没有回调,所以这里不需要 bindEnvironment。

    Meteor.startup(function () {
       if (Projects.find().count() === 0) {
         insertRecords();
       }
    });
    

    您的插入记录功能(使用 wrapAsync)因此您不需要回调

    function insertRecords() {
      console.log("inserting...");
      var client = Knox.createClient({
        key: apikey,
        secret: secret,
        bucket: 'profile-testing'
      });
          
      client.listSync = Meteor.wrapAsync(client.list.bind(client));
    
      console.log("created client");
          
      try {
          var data = client.listSync({ prefix: 'projects' });
      }
      catch(e) {
          console.log(e);
      }    
    
      if(!data) return;
    
    
      for (var i = 1; i < data.Contents.length; i++)  {
        console.log(data.Contents[i].Key);
        if (data.Contents[i].Key.split('/').pop() == "") {
          Projects.insert({ name: data.Contents[i].Key, contents: [] });
        } else if (data.Contents[i].Key.split('.').pop() == "jpg") {
          Projects.update( { name: data.Contents[i].Key.substr(0,
                             data.Contents[i].Key.lastIndexOf('.')) },
                           { $push: {contents: data.Contents[i].Key}} );
        } else {
          console.log(data.Contents[i].Key.split('.').pop());
        }
      }      
    });
    

    有几件事要记住。纤维不像线。 NodeJS 中只有一个线程。

    Fiber 更像是可以同时运行的事件,但如果存在等待类型的场景(例如从 Internet 下载文件),则不会相互阻塞。

    这样您就可以拥有同步代码而不会阻止其他用户的事件。它们轮流运行,但仍然在单个线程中运行。所以这就是 Meteor 在服务器端的同步代码,它可以等待东西,而其他用户不会被这个阻塞并且可以做东西,因为他们的代码在不同的光纤中运行。

    Chris Mather 在http://eventedmind.com 上有几篇关于此的好文章

    Meteor.wrapAsync 有什么作用?

    Meteor.wrapAsync 接受你给它的方法作为第一个参数并在当前纤程中运行它。

    它还附加了一个回调(它假定该方法采用最后一个具有回调的参数,其中第一个参数是错误,第二个参数是结果,例如function(err,result)

    回调与Meteor.bindEnvironment 绑定并阻塞当前的Fiber,直到回调被触发。一旦回调触发,它就会返回result 或抛出err

    因此,将异步代码转换为同步代码非常方便,因为您可以在下一行使用方法的结果,而不是使用回调和嵌套更深的函数。它还为您处理 bindEnvironment,因此您不必担心会丢失光纤的范围。

    更新Meteor._wrapAsync现在是Meteor.wrapAsyncdocumented

    【讨论】:

    • 感谢您澄清何时在光纤之间传递。你能详细解释一下client.listSync = Meteor._wrapAsync(client.list.bind(client)); 行的作用吗?
    • 用最后一位解释更新了答案。
    • 优秀的答案!既然wrapAsync 已被正式记录,还有机会更新它吗?
    猜你喜欢
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多