U gebruikt bindEnvironment enigszins onjuist. Omdat het wordt gebruikt al in een glasvezel en de callback die van de Knox-client komt niet meer in een glasvezel.
Er zijn twee use-cases van bindEnvironment (die ik kan bedenken, er kunnen er meer zijn!):
-
U heeft een globale variabele die moet worden gewijzigd, maar u wilt niet dat deze de sessies van andere gebruikers beïnvloedt
-
U beheert een terugbelverzoek met behulp van een api/npm-module van een derde partij (wat het geval lijkt te zijn)
Meteor.bindEnvironment
creëert een nieuwe Fiber en kopieert de huidige Fiber's variabelen en omgeving naar de nieuwe Fiber. Het punt dat je dit nodig hebt, is wanneer je de callback-methode van je nom-module gebruikt.
Gelukkig is er een alternatief dat ervoor zorgt dat de callback op je wacht en de callback bindt in een vezel genaamd Meteor.wrapAsync
.
Dus je zou dit kunnen doen:
Je opstartfunctie heeft al een fiber en geen callback, dus je hebt bindEnvironment hier niet nodig.
Meteor.startup(function () {
if (Projects.find().count() === 0) {
insertRecords();
}
});
En uw functie voor het invoegen van records (met behulp van wrapAsync), zodat u niet hoeft terug te bellen
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());
}
}
});
Een paar dingen om in gedachten te houden. Vezels zijn niet zoals draden. Er is maar één thread in NodeJS.
Fibers lijken meer op gebeurtenissen die tegelijkertijd kunnen worden uitgevoerd, maar zonder elkaar te blokkeren als er een wachtscenario is (bijvoorbeeld een bestand downloaden van internet).
U kunt dus synchrone code hebben en de gebeurtenissen van de andere gebruiker niet blokkeren. Ze rennen om de beurt, maar lopen nog steeds in een enkele thread. Dus zo heeft Meteor synchrone code aan de serverzijde, die kan wachten op dingen, maar andere gebruikers worden hierdoor niet geblokkeerd en kunnen dingen doen omdat hun code in een andere vezel loopt.
Chris Mather heeft een paar goede artikelen hierover op http://eventedmind.com
Wat doet Meteor.wrapAsync?
Meteor.wrapAsync
neemt de methode die je het geeft als de eerste parameter en voert het uit in de huidige vezel.
Het voegt er ook een callback aan toe (er wordt aangenomen dat de methode een laatste param heeft die een callback heeft waarbij de eerste param een fout is en de tweede het resultaat zoals function(err,result)
.
De callback is gebonden met Meteor.bindEnvironment
en blokkeert de huidige Fiber totdat de callback wordt geactiveerd. Zodra de callback wordt geactiveerd, wordt het result
. geretourneerd of gooit de err
.
Het is dus erg handig om asynchrone code om te zetten in synchrone code, omdat je het resultaat van de methode op de volgende regel kunt gebruiken in plaats van een callback en het nesten van diepere functies. Het zorgt ook voor de bindEnvironment voor u, zodat u zich geen zorgen hoeft te maken dat u het bereik van uw glasvezel verliest.
Bijwerken Meteor._wrapAsync
is nu Meteor.wrapAsync
en gedocumenteerd.