Ответ 1
Вы неправильно используете bindEnvironment. Потому что, когда его используют уже в волокне, и обратный вызов, который приходит от клиента Knox, больше не находится в волокне.
Есть два случая использования bindEnvironment (о которых я могу думать, их может быть больше!):
-
У вас есть глобальная переменная, которая должна быть изменена, но вы не хотите, чтобы она влияла на другие сеансы пользователя.
-
Вы управляете обратным вызовом с использованием стороннего модуля api/npm (что выглядит так)
Meteor.bindEnvironment
создает новое волокно и копирует текущие переменные волокна и среду в новое волокно. Точка, в которой вы нуждаетесь, - это когда вы используете обратный вызов метода номера модуля.
К счастью, есть альтернатива, которая заботится о обратном вызове, ожидающем вас, и связывает обратный вызов в волокне с именем 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
и блокирует текущее волокно, пока не будет вызван обратный вызов. Как только обратный вызов срабатывает, он возвращает result
или выбрасывает err
.
Так что это очень удобно для преобразования асинхронного кода в синхронный код, так как вы можете использовать результат метода на следующей строке вместо того, чтобы использовать обратный вызов и встраивать более глубокие функции. Он также заботится о bindEnvironment для вас, поэтому вам не нужно беспокоиться о потере объема вашего волокна.
Обновление Meteor._wrapAsync
теперь Meteor.wrapAsync
и задокументировано.