sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Qué está pasando con Meteor y Fibers/bindEnvironment()?

Está utilizando bindEnvironment de forma ligeramente incorrecta. Porque donde se usa ya está en una fibra y la devolución de llamada que sale del cliente Knox ya no está en una fibra.

Hay dos casos de uso de bindEnvironment (que se me ocurran, ¡podría haber más!):

  • Tiene una variable global que debe modificarse pero no quiere que afecte las sesiones de otros usuarios

  • Está administrando una devolución de llamada utilizando un módulo api/npm de terceros (que parece ser el caso)

Meteor.bindEnvironment crea una nueva fibra y copia las variables y el entorno de la fibra actual en la nueva fibra. El punto que necesita esto es cuando usa la devolución de llamada del método de su módulo nom.

Afortunadamente, existe una alternativa que se encarga de la devolución de llamada que te espera y vincula la devolución de llamada en una fibra llamada Meteor.wrapAsync .

Así que podrías hacer esto:

Su función de inicio ya tiene una fibra y no tiene devolución de llamada, por lo que no necesita bindEnvironment aquí.

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

Y su función de inserción de registros (usando wrapAsync) para que no necesite una devolución de llamada

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

Un par de cosas a tener en cuenta. Las fibras no son como los hilos. Solo hay un único hilo en NodeJS.

Las fibras son más como eventos que pueden ejecutarse al mismo tiempo pero sin bloquearse entre sí si hay un escenario de tipo de espera (por ejemplo, descargando un archivo de Internet).

Para que pueda tener un código síncrono y no bloquear los eventos de otros usuarios. Se turnan para ejecutarse, pero aún se ejecutan en un solo subproceso. Así es como Meteor tiene código síncrono en el lado del servidor, que puede esperar cosas, pero otros usuarios no serán bloqueados por esto y pueden hacer cosas porque su código se ejecuta en una fibra diferente.

Chris Mather tiene un par de buenos artículos sobre esto en http://eventedmind.com

¿Qué hace Meteor.wrapAsync?

Meteor.wrapAsync toma el método que le das como primer parámetro y lo ejecuta en la fibra actual.

También le adjunta una devolución de llamada (supone que el método toma un último parámetro que tiene una devolución de llamada donde el primer parámetro es un error y el segundo el resultado, como function(err,result) .

La devolución de llamada está vinculada con Meteor.bindEnvironment y bloquea la fibra actual hasta que se activa la devolución de llamada. Tan pronto como se activa la devolución de llamada, devuelve el result o lanza el err .

Por lo tanto, es muy útil para convertir código asíncrono en código síncrono, ya que puede usar el resultado del método en la línea siguiente en lugar de usar una devolución de llamada y anidar funciones más profundas. También se ocupa del bindEnvironment por usted para que no tenga que preocuparse por perder el alcance de su fibra.

Actualizar Meteor._wrapAsync ahora es Meteor.wrapAsync y documentado.