Nieco niepoprawnie używasz bindEnvironment. Ponieważ miejsce, w którym jest używany, znajduje się już w światłowodzie, a wywołanie zwrotne wychodzące z klienta Knox nie znajduje się już w światłowodzie.
Istnieją dwa przypadki użycia bindEnvironment (o których myślę, może być ich więcej!):
-
Masz zmienną globalną, którą należy zmienić, ale nie chcesz, aby wpływała na sesje innych użytkowników
-
Zarządzasz oddzwonieniem za pomocą zewnętrznego modułu API/npm (co wygląda na to)
Meteor.bindEnvironment
tworzy nowe światłowód i kopiuje zmienne i środowisko bieżącego światłowodu do nowego światłowodu. Potrzebujesz tego, gdy używasz wywołania zwrotnego metody modułu nom.
Na szczęście istnieje alternatywa, która zajmuje się czekającym na Ciebie wywołaniem zwrotnym i wiąże wywołanie zwrotne we włóknie o nazwie Meteor.wrapAsync
.
Więc możesz to zrobić:
Twoja funkcja startowa ma już światłowód i nie ma wywołania zwrotnego, więc nie potrzebujesz tutaj bindEnvironment.
Meteor.startup(function () {
if (Projects.find().count() === 0) {
insertRecords();
}
});
I funkcja wstawiania rekordów (za pomocą wrapAsync), dzięki czemu nie potrzebujesz wywołania zwrotnego
funkcjafunction 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());
}
}
});
Kilka rzeczy, o których należy pamiętać. Włókna nie są jak nici. W NodeJS jest tylko jeden wątek.
Światłowody przypominają bardziej zdarzenia, które mogą działać w tym samym czasie, ale bez wzajemnego blokowania, jeśli istnieje scenariusz typu oczekiwania (np. pobieranie pliku z Internetu).
Możesz więc mieć kod synchroniczny i nie blokować zdarzeń innych użytkowników. Biegną na zmianę, ale nadal działają w jednym wątku. W ten sposób Meteor ma synchroniczny kod po stronie serwera, który może czekać na rzeczy, ale inni użytkownicy nie będą przez to blokowani i mogą robić rzeczy, ponieważ ich kod działa w innym włóknie.
Chris Mather ma kilka dobrych artykułów na ten temat na http://eventedmind.com
Co robi Meteor.wrapAsync?
Meteor.wrapAsync
przyjmuje metodę, którą podałeś jako pierwszy parametr i uruchamia ją w bieżącym włóknie.
Dołącza również do niego wywołanie zwrotne (zakłada, że metoda przyjmuje ostatni parametr, który ma wywołanie zwrotne, w którym pierwszy parametr jest błędem, a drugi wynikiem, takim jak function(err,result)
.
Callback jest powiązany z Meteor.bindEnvironment
i blokuje bieżące światłowód do momentu uruchomienia wywołania zwrotnego. Jak tylko wywołanie zwrotne zwróci result
lub wyrzuca err
.
Jest to więc bardzo przydatne do konwertowania kodu asynchronicznego na kod synchroniczny, ponieważ można użyć wyniku metody w następnym wierszu zamiast używać wywołania zwrotnego i zagnieżdżania głębszych funkcji. Dba również o bindEnvironment za Ciebie, więc nie musisz się martwić o utratę zasięgu światłowodu.
Aktualizacja Meteor._wrapAsync
to teraz Meteor.wrapAsync
i udokumentowane.