MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Cosa sta succedendo con Meteor e Fibers/bindEnvironment()?

Stai usando bindEnvironment in modo leggermente errato. Perché dove viene utilizzato è già in una fibra e la richiamata che esce dal client Knox non è più in una fibra.

Ci sono due casi d'uso di bindEnvironment (che mi viene in mente, potrebbero essercene di più!):

  • Hai una variabile globale che deve essere modificata ma non vuoi che influisca sulle sessioni di altri utenti

  • Stai gestendo una richiamata utilizzando un modulo api/npm di terze parti (che sembra essere il caso)

Meteor.bindEnvironment crea una nuova fibra e copia le variabili e l'ambiente della fibra corrente nella nuova fibra. Il punto di cui hai bisogno è quando usi il callback del metodo del tuo modulo nom.

Fortunatamente c'è un'alternativa che si occupa della richiamata che ti aspetta e lega la richiamata in una fibra chiamata Meteor.wrapAsync .

Quindi potresti farlo:

La tua funzione di avvio ha già una fibra e nessun callback, quindi non hai bisogno di bindEnvironment qui.

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

E la tua funzione di inserimento record (usando wrapAsync) quindi non hai bisogno di una richiamata

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 paio di cose da tenere a mente. Le fibre non sono come i fili. C'è un solo thread in NodeJS.

Le fibre sono più simili a eventi che possono essere eseguiti contemporaneamente ma senza bloccarsi a vicenda se è presente uno scenario di tipo in attesa (ad es. download di un file da Internet).

Quindi puoi avere codice sincrono e non bloccare gli eventi dell'altro utente. Si alternano per correre ma continuano a funzionare in un unico thread. Quindi questo è il modo in cui Meteor ha un codice sincrono sul lato server, che può aspettare cose, ma gli altri utenti non saranno bloccati da questo e possono fare cose perché il loro codice viene eseguito su una fibra diversa.

Chris Mather ha un paio di buoni articoli su questo su http://eventedmind.com

Cosa fa Meteor.wrapAsync?

Meteor.wrapAsync prende il metodo che gli dai come primo parametro e lo esegue nella fibra corrente.

Allega anche un callback (presume che il metodo prenda un ultimo parametro che ha un callback in cui il primo parametro è un errore e il secondo il risultato come function(err,result) .

La richiamata è associata a Meteor.bindEnvironment e blocca la fibra corrente fino a quando non viene attivata la richiamata. Non appena la richiamata viene attivata, restituisce il result o lancia il err .

Quindi è molto utile per convertire il codice asincrono in codice sincrono poiché puoi usare il risultato del metodo sulla riga successiva invece di usare un callback e annidare funzioni più profonde. Si occupa anche del bindEnvironment per te, quindi non devi preoccuparti di perdere l'ambito della tua fibra.

Aggiorna Meteor._wrapAsync ora è Meteor.wrapAsync e documentato.