Я изо всех сил пытаюсь понять, как я могу вернуть данные из нескольких обещаний для создания массива данных.
Могу ли я в любом случае вернуть данные за пределы обещания, чтобы нажать на переменную данных?
У меня есть следующее:
db_sh.find({
selector: {sh: req.params.sh_id},
fields: ['_id', 'sh_id', 'time'],
sort: ['_id']
}).then(function (result) {
let data = {};
console.info('Found: ' + result.docs.length);
if (result.docs.length > 0) {
for (var i = 0; i < result.docs.length; i++) {
let student = result.docs[i];
Promise
.all([getMealBooking(student._id), getStudentData(student._id)])
.then(function(response) {
var meal_booking_data = response[0];
var student_data = response[1];
console.info(meal_booking_data);
console.info(student_data);
})
.catch(function (err) {
return res.send(false);
});
data[student.time] = [
meal_booking_data,
student_data
]
}
}
/** Sort Data Oldest First*/
data = Object.keys(data).sort().reduce((a, c) => (a[c] = data[c], a), {});
console.info(data);
res.send(data);
});
У меня есть два обещания (getMealBooking() и getStudentData()): и я использую Promise.all(), чтобы вернуть мне результаты обоих этих обещаний. Я пытался вернуть данные, но не могу получить результаты для создания массива данных.
Любая помощь, чтобы иметь возможность составить список всех моих данных, была бы отличной.
Нет возможности «вернуть данные за пределы обещания» — асинхронность остается асинхронной.
let arr = [];
const datas = await Promise.all([
getMealBooking(),
getStudentData()
]);
arr.push(datas[0]); //adds getMealBooking() results
arr.push(datas[1]); // adds getStudentData() results
Сделать функцию не сложно async
.
getMealBooking() и getStudentData() являются асинхронными функциями?
Я не мог использовать await, так как это был верхний уровень в конечной точке node js express.js.
@heady12 Heady12 Вы можете использовать ожидание верхнего уровня во всех поддерживаемых в настоящее время версиях Node.js с использованием модулей.
Извините, я только что узнал, что могу сделать экспресс-функции .get() асинхронными. Да, ожидание работает нормально :)
Вы также можете использовать IIFE в качестве обходного пути, если ожидание верхнего уровня не подходит.
Вам нужно два Promise.all
— один для перебора каждого ученика и вложенный для получения getMealBooking
и getStudentData
для каждого ученика.
Поместите все в асинхронную функцию (которая перехватывает и отправляет false
при необходимости), чтобы облегчить понимание потока управления.
const { docs } = await db_sh.find({
selector: { sh: req.params.sh_id },
fields: ['_id', 'sh_id', 'time'],
sort: ['_id']
});
if (docs.length === 0) {
// no data; stop here
res.send({});
return;
};
const data = {};
await Promise.all(
docs.map(student => (
Promise.all([getMealBooking(student._id), getStudentData(student._id)])
.then(([mealBookingData, studentData]) => {
data[student.time] = [mealBookingData, studentData];
})
))
);
const sortedData = Object.keys(data).sort().reduce((a, c) => (a[c] = data[c], a), {});
res.send(sortedData);
См. редактирование OP, в котором теперь все зависит от ученика.
Извините, я пропустил передачу идентификатора студента в вызовы getMealData() и getStudentData(). Спасибо за ваш ответ, только что изучивший, как работают промисы JS, и это очень помогло с цепочкой then() и возвратом Promise.all(). Спасибо, что поделились этим подходом :)
@heady12 Хорошо, см. правку
Спасибо за ваш ответ, вы действительно помогли мне своими ответами понять, что происходит. К сожалению, эта логика находится в моей конечной точке express.js, и я не могу использовать await (SyntaxError: await допустимо только в асинхронных функциях и телах модулей верхнего уровня). Я принял ответ Дана, поскольку я использовал его подход, но обязательно вернусь к этому. Огромное спасибо :)
@heady12 Heady12 Как говорится в моем ответе, вы должны сделать функцию асинхронной — вам просто нужно добавить ключевое слово async
. (Не бойтесь использовать асинхронные функции, они часто значительно упрощают понимание асинхронного кода. Здесь нет пользы тонна, но это неплохо)
Извините, я не знал, что могу сделать конечные точки express.js асинхронными, просто увидел, что они могут, лол. Спасибо еще раз. Я только что проверил ваш код, но по какой-то причине он просто возвращает 1 в качестве данных?
@ heady12 Он не должен возвращать 1; все вызовы res.send
возвращают объект
Извините, я допустил ошибку в своем запросе, данные возвращали 1, когда у меня была ошибка от pouchdb - код работает нормально :) Еще раз спасибо
Принято. Этот ответ - код чище и проще для понимания - хотя ответ danh также полезен. Спасибо обоим.
Еще один Promise.all()
нужен для цикла, содержащего Promise.all()
, о котором вы уже догадались. Лучше немного учитывать, чтобы вы могли видеть, что происходит.
function getStudentMealAndData(student) {
return Promise
.all([getMealBooking(student._id), getStudentData(student._id)])
.then(function(response) {
var meal_booking_data = response[0];
var student_data = response[1];
console.info(meal_booking_data);
console.info(student_data);
return { student, meal_booking_data, student_data };
})
.catch(function (err) {
return res.send(false);
});
}
Это немного упрощает блок then...
}).then(function (result) {
console.info('Found: ' + result.docs.length);
let promises = []
for (var i = 0; i < result.docs.length; i++) {
let student = result.docs[i];
promises.push(getStudentMealAndData(student));
}
return Promise.all(promises);
}).then(results => {
// results are an array of [{ student, meal_booking_data, student_data }, ...]
let data = results.reduce((acc, s) => {
acc[s.student.time] = [ s.meal_booking_data, s.student_data ];
return acc;
}, {});
data = Object.keys(data).sort().reduce((a, c) => (a[c] = data[c], a), {});
console.info(data);
res.send(data);
});
Отвечает ли это на ваш вопрос? Как вернуть ответ на асинхронный вызов