Существует ли чистый подход, основанный на обещаниях для сопоставления/конкатенации коллекций?
async vs. Q вообще
Я изучаю разработку Node.js и пытаюсь обернуть мозг вокруг стратегий управления асинхронным "обратным адским". Две основные стратегии, которые я изучил, - это Caolan McMahon async, а Kris Kowal - на основе Q.
Как многие другие люди, я все еще пытаюсь понять, когда вы должны использовать один против другого. Однако, вообще говоря, я обнаружил, что promises и Q-код немного интуитивны, поэтому я двигался в этом направлении.
Сопоставление/объединение общих коллекций
Тем не менее, я все еще застрял, используя функции async для управления коллекциями. Исходя из фона Java и Python, большую часть времени, когда я работаю с коллекцией, логика выглядит так:
- Инициализировать новую пустую коллекцию, в которой хранятся результаты.
- Выполните цикл for-each со старой коллекцией, применяя некоторую логику к каждому элементу и подталкивая его результат в новую пустую коллекцию.
- Когда цикл for-each завершается, перейдите к использованию новой коллекции.
В клиентском JavaScript я привык использовать функцию jQuery map(), проходящую в этом шаге # 2 логики, и получение результата №3 в качестве возвращаемого значения. Похож на тот же базовый подход.
Сопоставление/Объединение коллекций с помощью async и Q
Асинхронный модуль Node -side имеет аналогичный map и concat, но они не возвращают конкатенированный результат обратно на исходный уровень. Вместо этого вы должны спуститься в аддон обратного вызова, чтобы использовать результат. Пример:
var deferred = Q.defer();
...
var entries = [???]; // some array of objects with "id" attributes
async.concat(entries, function (entry, callback) {
callback(null, entry.id);
}, function (err, ids) {
// We now have the "ids" array, holding the "id" attributes of all items in the "entries" array.
...
// Optionaly, perhaps do some sorting or other post-processing on "ids".
...
deferred.resolve(ids);
});
...
return deferred.promise;
Поскольку мои другие функции становятся на основе обещаний, у меня есть этот код, возвращающий объект обещания, поэтому его можно легко включить в цепочку then()
.
Мне действительно нужны оба?
Окончательный вопрос, который я изо всех сил пытаюсь сформулировать, заключается в следующем: действительно ли мне нужен как асинхронный , так и Q в приведенном выше примере кода? Я изучаю, как заменить поток управления асинхронным модулем с помощью цепей обещаний Q-стиля вообще... но он еще не "нажал" для меня, как делать сопоставление или объединение коллекций с помощью подхода, основанного на обещаниях. В качестве альтернативы, я хотел бы понять, почему вы не можете или почему это не очень хорошая идея.
Если async и Q предназначены для совместной работы, поскольку я использую их в приведенном выше примере, то пусть будет так. Но я бы предпочел не требовать дополнительной зависимости от библиотеки, если бы мог чисто использовать Q.
(Извините, если я пропустил что-то невероятно очевидное. Асинхронная модель, управляемая событиями, - это совсем другой мир, и моя голова все еще плавает.)
Ответы
Ответ 1
Мне действительно нужны оба?
Нет. Сопоставление асинхронных итераторов по коллекции довольно просто с помощью promises, но для вызова функции требуется два шага. Во-первых, коллекция map
ped для массива promises для параллельной итерации. Затем эти promises подаются в Q.all
, чтобы сделать одно обещание для отображенной коллекции. В отличие от async
, порядок результата гарантирован.
var entries = […]; // some array of objects with "id" attributes
var promises = entries.map(function(object) {
return asyncPromiseReturingFunction(object);
}); // the anonymous wrapper might be omitted
return Q.all(promises);
Для concat
вам нужно добавить
.then(function(results) {
return Array.prototype.concat.apply([], results);
});