Javascript - работа с несколькими обещаниями внутри цикла - как вернуть данные вне обещания?

Я изо всех сил пытаюсь понять, как я могу вернуть данные из нескольких обещаний для создания массива данных.

Могу ли я в любом случае вернуть данные за пределы обещания, чтобы нажать на переменную данных?

У меня есть следующее:

db_sh.find({
    selector: {sh: req.params.sh_id},
    fields: ['_id', 'sh_id', 'time'],
    sort: ['_id']
}).then(function (result) {
    let data = {};
    console.log('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.log(meal_booking_data);

                    console.log(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.log(data);
    res.send(data);
});

У меня есть два обещания (getMealBooking() и getStudentData()): и я использую Promise.all(), чтобы вернуть мне результаты обоих этих обещаний. Я пытался вернуть данные, но не могу получить результаты для создания массива данных.

Любая помощь, чтобы иметь возможность составить список всех моих данных, была бы отличной.

Отвечает ли это на ваш вопрос? Как вернуть ответ на асинхронный вызов

jonrsharpe 17.05.2022 02:24

Нет возможности «вернуть данные за пределы обещания» — асинхронность остается асинхронной.

Bravo 17.05.2022 02:32
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
2
2
32
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

let arr = [];
const datas = await Promise.all([
    getMealBooking(),
    getStudentData()
]);
arr.push(datas[0]); //adds getMealBooking() results
arr.push(datas[1]); // adds getStudentData() results

Сделать функцию не сложно async.

chaoskreator 17.05.2022 02:28

getMealBooking() и getStudentData() являются асинхронными функциями?

heady12 17.05.2022 02:29

Я не мог использовать await, так как это был верхний уровень в конечной точке node js express.js.

heady12 17.05.2022 02:53

@heady12 Heady12 Вы можете использовать ожидание верхнего уровня во всех поддерживаемых в настоящее время версиях Node.js с использованием модулей.

jabaa 17.05.2022 02:54

Извините, я только что узнал, что могу сделать экспресс-функции .get() асинхронными. Да, ожидание работает нормально :)

heady12 17.05.2022 03:00

Вы также можете использовать IIFE в качестве обходного пути, если ожидание верхнего уровня не подходит.

chaoskreator 17.05.2022 03:06
Ответ принят как подходящий

Вам нужно два 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, в котором теперь все зависит от ученика.

danh 17.05.2022 02:28

Извините, я пропустил передачу идентификатора студента в вызовы getMealData() и getStudentData(). Спасибо за ваш ответ, только что изучивший, как работают промисы JS, и это очень помогло с цепочкой then() и возвратом Promise.all(). Спасибо, что поделились этим подходом :)

heady12 17.05.2022 02:32

@heady12 Хорошо, см. правку

CertainPerformance 17.05.2022 02:48

Спасибо за ваш ответ, вы действительно помогли мне своими ответами понять, что происходит. К сожалению, эта логика находится в моей конечной точке express.js, и я не могу использовать await (SyntaxError: await допустимо только в асинхронных функциях и телах модулей верхнего уровня). Я принял ответ Дана, поскольку я использовал его подход, но обязательно вернусь к этому. Огромное спасибо :)

heady12 17.05.2022 02:52

@heady12 Heady12 Как говорится в моем ответе, вы должны сделать функцию асинхронной — вам просто нужно добавить ключевое слово async. (Не бойтесь использовать асинхронные функции, они часто значительно упрощают понимание асинхронного кода. Здесь нет пользы тонна, но это неплохо)

CertainPerformance 17.05.2022 02:53

Извините, я не знал, что могу сделать конечные точки express.js асинхронными, просто увидел, что они могут, лол. Спасибо еще раз. Я только что проверил ваш код, но по какой-то причине он просто возвращает 1 в качестве данных?

heady12 17.05.2022 02:58

@ heady12 Он не должен возвращать 1; все вызовы res.send возвращают объект

CertainPerformance 17.05.2022 03:00

Извините, я допустил ошибку в своем запросе, данные возвращали 1, когда у меня была ошибка от pouchdb - код работает нормально :) Еще раз спасибо

heady12 17.05.2022 03:05

Принято. Этот ответ - код чище и проще для понимания - хотя ответ danh также полезен. Спасибо обоим.

heady12 17.05.2022 03:08

Еще один 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.log(meal_booking_data);
      console.log(student_data);
      return { student, meal_booking_data, student_data };
    })
    .catch(function (err) {
      return res.send(false);
    });
}

Это немного упрощает блок then...

}).then(function (result) {
    console.log('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.log(data);
    res.send(data);
});

Другие вопросы по теме