Meteor和Fibers/bindEnvironment()发生了什么?

tro*_*mug 16 mongodb node.js meteor node-fibers

我在使用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();
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

我第一次写这个,我得到的错误是我需要将我的回调包装在一个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++中的线程/带有线程的每种语言,但我不明白扩展到我的服务器端代码的含义是什么/为什么我的代码在尝试插入时会抛出错误一个集合.任何人都可以向我解释这个吗?

谢谢.

Aks*_*hat 20

您使用bindEnvironment略有错误.因为它的使用位置已经在光纤中,并且Knox客户端发出的回调不再是光纤.

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

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

  • 您正在使用第三方api/npm模块管理回调(看起来就是这种情况)

Meteor.bindEnvironment创建新光纤并将当前光纤的变量和环境复制到新光纤.您需要这一点是在使用nom模块的方法回调时.

幸运的是,有一种替代方法可以处理等待你的回调并将回调绑定在一个叫做的光纤中Meteor.wrapAsync.

所以你可以这样做:

你的启动函数已经有了光纤而没有回调,因此你不需要在这里使用bindEnvironment.

Meteor.startup(function () {
   if (Projects.find().count() === 0) {
     insertRecords();
   }
});
Run Code Online (Sandbox Code Playgroud)

并且您的插入记录功能(使用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());
    }
  }      
});
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Meteor.wrapAsync做什么?

Meteor.wrapAsync 接受您提供的方法作为第一个参数并在当前光纤中运行它.

它还附加一个回调函数(它假设该方法采用最后一个参数,其中第一个参数是一个错误,第二个结果是function(err,result).

回调绑定Meteor.bindEnvironment并阻止当前光纤,直到触发回调为止.一旦回调触发它返回result或抛出err.

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

Meteor._wrapAsync现在更新Meteor.wrapAsync记录在案.