Блюберд обещает каждому не вернуть последний результат
Я использую promise.each
перебрать запрос 2 дБ с помощью bookshelfjs
, но роли не дают мне этого результата -> roles[resource.get('name')] = role.get('name');
, но это дает мне объект из утверждения выбора:
var promise = new Promise(
function resolver(resolve, reject) {
var roles = {};
Promise.each(user.relations.relates.models, function(relation){
return Resource.forge({resourceId: relation.get('resourceId')}).fetch().then(function(resource){
return Role.forge({roleId: relation.get('roleId')}).fetch().then(function(role){
roles[resource.get('name')] = role.get('name');
return roles;
}).catch(function(err){
reject({"status":"error", "data": err});
});
}).catch(function(err){
reject({"status":"error", "data": err});
});
}).then(function(roles){
resolve(roles);
});
}
);
return promise;
2 ответа
Из документов Bluebird для Promise.each()
:
Разрешает исходный массив без изменений, этот метод предназначен для побочных эффектов.
Итак, это означает, что когда вы делаете:
Promise.each(array).then(function(val) {
// iteration finished here
// val is the original array
});
Тот val
будет исходный массив, который вы передали, а не ваш roles
объект.
Потому что ваш roles
Объект находится в более высоком объеме, вы можете удалить параметр, объявленный как roles
в вашем .then()
обработчик и просто напрямую относится к более высокой области roles
переменная.
Вам также следует избегать анти-паттерна конструктора обещаний и не создавать новое обещание, а просто вернуть то, которое у вас уже есть.
Вы можете сделать это так:
var roles = {};
return Promise.each(user.relations.relates.models, function (relation) {
return Resource.forge({resourceId: relation.get('resourceId')}).fetch().then(function (resource) {
return Role.forge({roleId: relation.get('roleId')}).fetch().then(function (role) {
roles[resource.get('name')] = role.get('name');
});
}).catch(function (err) {
// repackage how the error is presented into our own object
throw ({"status": "error", "data": err});
});
}).then(function () {
// make the resolved value of the final promise be the roles object
return roles;
});
Разрешенное значение этого возвращенного обещания будет вашим roles
объект.
Сводка изменений:
- Верните обещание от
Promise.each()
вместо создания нового обещания (нет необходимости создавать новое обещание здесь). - Пусть отклонения распространяются обратно, нет необходимости вручную отклонять обещание более высокого уровня.
- в
.then()
обработчик дляPromise.each()
удалите объявленный параметр с именемroles
так как это конфликтует с вашей высшей областьюroles
объект. - Вернуть
roles
в этом.then()
обработчик, поэтому он становится решающим значением обещания, которое вы возвращаете. - Удалить внутренний
.catch()
так как внешний.catch()
может сделать свою работу тоже. - Изменить
.catch()
бросить перепакованное значение ошибки. - Удалить внутренний
return roles;
так как это не нужно.roles
объект постоянно доступен в большем объеме, поэтому нет необходимости делать его разрешенным значением этих внутренних обещаний (на самом деле, это может создать путаницу).
Возможна оптимизация производительности. Поскольку ни один из ваших результатов не зависит от предыдущих результатов, кажется, что, возможно, вы могли бы выполнять все свои асинхронные операции параллельно, а не последовательно, и в этом случае вы могли бы заменить Promise.each()
с Promise.map()
,
Да, извините, мы передумали.
В 3.х мы должны были сделать .each
возвращать результаты, а не исходные значения, но это сломало код для многих людей, поэтому мы изменили его и добавили mapSeries
,
В основном, используйте .mapSeries
всякий раз, когда вы используете each
и заботиться о результатах, он делает именно то, что вы ожидаете. Если вы можете запустить элементы одновременно, используйте .map
хотя, поскольку это, вероятно, будет работать намного лучше.