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.