Как я могу сделать рекурсивный вызов Promise возвратом для сокращения в Javascript?

Я пытаюсь создать рекурсивный вызов Promise внутри reduce в JS. Цель моей системы здесь состоит в том, чтобы сделать n больших вызовов для каждого элемента в массиве, с которым reduce играет, затем, если внутри этого reduce этот большой вызов решит, что ему нужно n меньших вызовов, прежде чем он вернется к большим, тогда reduce не следует переходить к следующему пункту, просто дождитесь его окончания.

Мой текущий код:

function download_preliminary_files_1() {
    let demo_schema_download = new Base_Ajax_Requester(
        localized_data.ajax_url,
        {
            'ajax_action': 'download_demo_file_schema',
            'ajax_nonce': localized_data.ajax_nonce,
            'backend': {
                'data_handle': 'download_demo_file_schema_data',
                'data':
                    {
                        'demo_handle' : 'demo-2',
                    }
            }
        }
    );

    let import_files_download = demo_schema_download.call().then(function() {
        fake_data.steps_to_import.reduce(function(previous_promise, next_step_identifier) {
            return previous_promise.then(function() {
                let file_download = download_demo_file({
                    'demo_handle' : 'demo-2',
                    'step' : next_step_identifier
                }).call();

                file_download.then(function(response) {
                    /**
                     * Here, if I detect that response.remaining_number_of_files > 0, I should start
                     * a chain that keeps calling `download_demo_file` with new parameters.
                     *
                     * Then, when this chain is done, resume the normal reduce behavior.
                     */
                });
            });
        }, Promise.resolve())
    }).catch(function(error) {
        console.info( 'Got this error:' + error);
    });

    return import_files_download;
}

Где Base_Ajax_Requester — это вспомогательный класс, который обрабатывает запросы AJAX и возвращает Promise, когда это делается, чтобы вокруг него можно было написать код.

Мой fake_data это:

let fake_data = {
    'demo_handle' : 'demo-2',
    'steps_to_import' : [ 'elementor-hf','post', 'nav_menu' ]
}

Как видите, fake_data.steps_to_import.reduce(.. пройдет через эти 3 значения, для каждого из них вызовите download_demo_file, дождитесь его окончания, затем перейдите к следующему. Можно сказать, что я хотел бы, чтобы между elementor-hf и post было n меньших вызовов.

Первоначальный вызов download_demo_file виден там, вот что всегда будет возвращаться из серверной части:

{
    'message' : '...',
    'file_number' : 1, //Which -n.xml file has been downloaded where n is this number.
    'remaining_number_of_files' : 1 //Calculates, based on what file was downloaded how many files are left. The system knows internally how many files it has to download.
}

Повторный вызов, опять же, с download_demo_file будет выглядеть так:

{
    'demo_handle' : 'demo-2',
    'step' : next_step_identifier,
    'file_counter' : 2 //Dynamic. This will signal that it needs to now download file-2.xml.
}

...и так далее, пока сервер не отправит remaining_number_of_files : 0, затем все останавливается, потому что больше нет файлов для загрузки, и можно перейти к следующему большому вызову.

Как я могу этого добиться?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
40
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Внутри каждого обратного вызова reduce я бы сделал функцию, которая вызывает download_demo_file (с изменяющимся file_counter), и после того, как этот Promise разрешается, рекурсивно возвращает вызов самого себя, если remaining_number_of_files > 0. Это будет означать, что getProm() будет постоянно вызывать себя до тех пор, пока условие remaining_number_of_files > 0 больше не будет выполняться, и что только после этого будет разрешен весь промис для этой конкретной reduce итерации.

let import_files_download = demo_schema_download.call().then(function() {
  fake_data.steps_to_import.reduce(function(previous_promise, step) {
    let file_counter = 1;
    return previous_promise.then(function() {
      const getProm = () => download_demo_file({
        demo_handle: 'demo-2',
        step,
        file_counter
      }).call()
        .then((response) => {
          file_counter++;
          return response.remaining_number_of_files > 0
            ? getProm()
            : response
        });
      return getProm();
    });
  }, Promise.resolve())
}).catch(function(error) {
  console.info('Got this error:' + error);
});

Код, вероятно, будет много легче читать и понимать с async/await, хотя:

await demo_schema_download.call();
const import_files_download = [];
for (const step of fake_data.steps_to_import) {
  let response;
  let file_counter = 1;
  do {
    response = await download_demo_file({
      demo_handle: 'demo-2',
      step,
      file_counter
    }).call();
    file_counter++;
  } while (response.remaining_number_of_files > 0);
  import_files_download.push(response); // is this needed?
}
return import_files_download; // is this needed?

Перехватите потребителя асинхронной функции.

Я не могу использовать async/await из-за ненадежности ограничений совместимости и полифиллов.

coolpasta 23.06.2019 06:30

Кроме того, ваш код теоретически работает, но на данный момент это не так, потому что я не передаю новые параметры (поэтому система не может сказать, что появился новый флаг file_counter. Не могли бы вы обновить код, и я знаю, что это у меня много вопросов, но я обещаю, что это будет использовано с пользой - не могли бы вы немного объяснить, что происходит?

coolpasta 23.06.2019 06:34

Должно быть достаточно просто, просто следите за file_counter, который увеличивается.

CertainPerformance 23.06.2019 06:40

Безусловно! Но в ? getProm(), если я передам этот новый параметр, ничего не произойдет. Мысли?

coolpasta 23.06.2019 06:45

Поскольку file_counter находится во внешней области (обратного вызова .reduce), не должно быть необходимости передавать параметр file_counter (хотя я думаю, вы можете сделать это, если хотите) - он увеличивается внутри .call().then, и также виден download_demo_file

CertainPerformance 23.06.2019 06:48

Похоже, вы используете ES6 — если вы не используете Babel или уже ориентируетесь на среды ES6+, вы можете использовать await путем транспиляции безregeneratorRuntime, если это проблема. Преобразование относительно простой из функции async в генератор.

CertainPerformance 23.06.2019 07:01

Давайте продолжить обсуждение в чате.

coolpasta 23.06.2019 07:02

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