Sie verwenden bindEnvironment etwas falsch. Denn wo es verwendet wird, befindet es sich bereits in einer Glasfaser und der Rückruf, der vom Knox-Client kommt, befindet sich nicht mehr in einer Glasfaser.
Es gibt zwei Anwendungsfälle von bindEnvironment (die mir einfallen, es könnten noch mehr sein!):
-
Sie haben eine globale Variable, die geändert werden muss, aber Sie möchten nicht, dass sie sich auf die Sitzungen anderer Benutzer auswirkt
-
Sie verwalten einen Rückruf mit einem api/npm-Modul eines Drittanbieters (was der Fall zu sein scheint)
Meteor.bindEnvironment
erstellt eine neue Fiber und kopiert die Variablen und die Umgebung der aktuellen Fiber in die neue Fiber. Der Punkt, an dem Sie dies benötigen, ist, wenn Sie den Methoden-Callback Ihres nom-Moduls verwenden.
Glücklicherweise gibt es eine Alternative, die sich um den auf Sie wartenden Rückruf kümmert und den Rückruf in eine Faser namens Meteor.wrapAsync
bindet .
Sie könnten also Folgendes tun:
Ihre Startfunktion hat bereits eine Glasfaser und keinen Rückruf, sodass Sie hier keine bindEnvironment benötigen.
Meteor.startup(function () {
if (Projects.find().count() === 0) {
insertRecords();
}
});
Und Ihre Funktion zum Einfügen von Datensätzen (mit WrapAsync), sodass Sie keinen Rückruf benötigen
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());
}
}
});
Ein paar Dinge, die Sie beachten sollten. Fasern sind nicht wie Fäden. Es gibt nur einen einzigen Thread in NodeJS.
Fasern sind eher wie Ereignisse, die gleichzeitig ausgeführt werden können, sich aber nicht gegenseitig blockieren, wenn ein Warteszenario vorliegt (z. B. Herunterladen einer Datei aus dem Internet).
So können Sie synchronen Code haben und die Ereignisse des anderen Benutzers nicht blockieren. Sie wechseln sich ab, laufen aber immer noch in einem einzigen Thread. So hat Meteor serverseitig synchronen Code, der auf Dinge warten kann, aber andere Benutzer werden dadurch nicht blockiert und können Dinge tun, weil ihr Code in einer anderen Faser läuft.
Chris Mather hat ein paar gute Artikel dazu auf http://eventedmind.com
Was macht Meteor.wrapAsync?
Meteor.wrapAsync
übernimmt die Methode, die Sie als ersten Parameter angeben, und führt sie in der aktuellen Fiber aus.
Es hängt auch einen Rückruf an (es wird davon ausgegangen, dass die Methode einen letzten Parameter mit einem Rückruf verwendet, wobei der erste Parameter ein Fehler und der zweite das Ergebnis ist, z. B. function(err,result)
.
Der Rückruf wird mit Meteor.bindEnvironment
gebunden und blockiert die aktuelle Faser, bis der Rückruf ausgelöst wird. Sobald der Callback ausgelöst wird, gibt er das result
zurück oder wirft den err
.
Es ist also sehr praktisch, asynchronen Code in synchronen Code umzuwandeln, da Sie das Ergebnis der Methode in der nächsten Zeile verwenden können, anstatt einen Rückruf zu verwenden und tiefere Funktionen zu verschachteln. Es kümmert sich auch um die bindEnvironment für Sie, so dass Sie sich keine Sorgen machen müssen, den Geltungsbereich Ihrer Faser zu verlieren.
Aktualisieren Meteor._wrapAsync
ist jetzt Meteor.wrapAsync
und dokumentiert.