MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Que se passe-t-il avec Meteor et Fibers/bindEnvironment() ?

Vous utilisez bindEnvironment de manière légèrement incorrecte. Parce que là où il est utilisé, c'est déjà dans une fibre et le rappel qui vient du client Knox n'est plus dans une fibre.

Il existe deux cas d'utilisation de bindEnvironment (auxquels je peux penser, il pourrait y en avoir plus !) :

  • Vous avez une variable globale qui doit être modifiée mais vous ne voulez pas qu'elle affecte les sessions des autres utilisateurs

  • Vous gérez un rappel à l'aide d'un module api/npm tiers (ce qui semble être le cas)

Meteor.bindEnvironment crée une nouvelle fibre et copie les variables et l'environnement de la fibre actuelle dans la nouvelle fibre. Le point dont vous avez besoin est lorsque vous utilisez le rappel de méthode de votre module nom.

Heureusement, il existe une alternative qui prend en charge le rappel qui vous attend et lie le rappel dans une fibre appelée Meteor.wrapAsync .

Vous pouvez donc faire ceci :

Votre fonction de démarrage a déjà une fibre et aucun rappel, vous n'avez donc pas besoin de bindEnvironment ici.

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

Et votre fonction d'insertion d'enregistrements (à l'aide de wrapAsync) pour que vous n'ayez pas besoin de rappel

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

Quelques éléments à garder à l'esprit. Les fibres ne sont pas comme les fils. Il n'y a qu'un seul thread dans NodeJS.

Les fibres ressemblent plus à des événements qui peuvent s'exécuter en même temps mais sans se bloquer s'il y a un scénario de type attente (par exemple, télécharger un fichier depuis Internet).

Ainsi, vous pouvez avoir un code synchrone et ne pas bloquer les événements de l'autre utilisateur. Ils s'exécutent à tour de rôle, mais s'exécutent toujours dans un seul thread. C'est ainsi que Meteor a du code synchrone côté serveur, qui peut attendre des choses, mais les autres utilisateurs ne seront pas bloqués par cela et pourront faire des choses parce que leur code s'exécute dans une fibre différente.

Chris Mather a quelques bons articles à ce sujet sur http://eventedmind.com

Que fait Meteor.wrapAsync ?

Meteor.wrapAsync prend la méthode que vous lui donnez comme premier paramètre et l'exécute dans la fibre actuelle.

Il y attache également un rappel (il suppose que la méthode prend un dernier paramètre qui a un rappel où le premier paramètre est une erreur et le second le résultat tel que function(err,result) .

Le rappel est lié à Meteor.bindEnvironment et bloque la fibre actuelle jusqu'à ce que le rappel soit déclenché. Dès que le rappel se déclenche, il renvoie le result ou lance le err .

C'est donc très pratique pour convertir du code asynchrone en code synchrone puisque vous pouvez utiliser le résultat de la méthode sur la ligne suivante au lieu d'utiliser un rappel et d'imbriquer des fonctions plus profondes. Il prend également en charge le bindEnvironment pour vous afin que vous n'ayez pas à vous soucier de perdre la portée de votre fibre.

Mettre à jour Meteor._wrapAsync est maintenant Meteor.wrapAsync et documenté.