Използвате bindEnvironment малко неправилно. Защото мястото, където се използва, вече е във влакно и обратното извикване, което идва от клиента на Knox, вече не е във влакно.
Има два случая на използване на bindEnvironment (за които се сещам, може да има още!):
-
Имате глобална променлива, която трябва да бъде променена, но не искате тя да засяга сесиите на други потребители
-
Вие управлявате обратно повикване с помощта на модул api/npm на трета страна (което изглежда е така)
Meteor.bindEnvironment
създава ново Fiber и копира текущите променливи и средата на Fiber в новото Fiber. Това, от което се нуждаете, е, когато използвате обратното извикване на метода на вашия nom модул.
За щастие има алтернатива, която се грижи за чакащото ви обратно извикване и свързва обратното извикване във влакно, наречено Meteor.wrapAsync
.
Така че можете да направите това:
Функцията ви за стартиране вече има влакно и няма обратно извикване, така че нямате нужда от bindEnvironment тук.
Meteor.startup(function () {
if (Projects.find().count() === 0) {
insertRecords();
}
});
И вашата функция за вмъкване на записи (използвайки wrapAsync), така че нямате нужда от обратно извикване
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());
}
}
});
Няколко неща, които трябва да имате предвид. Влакната не са като нишки. В NodeJS има само една нишка.
Влакната са по-скоро събития, които могат да се изпълняват по едно и също време, но без да се блокират взаимно, ако има сценарий от тип на изчакване (напр. изтегляне на файл от интернет).
Така че можете да имате синхронен код и да не блокирате събитията на другия потребител. Те се редуват, за да бягат, но все пак работят в една нишка. Ето как Meteor има синхронен код от страна на сървъра, който може да чака за неща, но други потребители няма да бъдат блокирани от това и могат да правят неща, защото техният код работи в различно влакно.
Крис Матер има няколко добри статии за това на http://eventedmind.com
Какво прави Meteor.wrapAsync?
Meteor.wrapAsync
приема метода, който сте му дали като първи параметър, и го изпълнява в текущото влакно.
Той също така прикачва обратно извикване към него (предполага, че методът приема последен параметър, който има обратно извикване, където първият параметър е грешка, а вторият резултат като function(err,result)
.
Обратното извикване е обвързано с Meteor.bindEnvironment
и блокира текущото Fiber, докато не бъде задействано обратното повикване. Веднага след като се задейства обратното извикване, той връща result
или хвърля err
.
Така че е много удобно за конвертиране на асинхронен код в синхронен код, тъй като можете да използвате резултата от метода на следващия ред, вместо да използвате обратно извикване и да влагате по-дълбоки функции. Той също така се грижи за bindEnvironment вместо вас, така че не е нужно да се притеснявате, че ще загубите обхвата на вашето влакно.
Актуализиране Meteor._wrapAsync
вече е Meteor.wrapAsync
и документирано.