简体   繁体   English

如何在 Javascript 中进行递归 Promise 调用以作为 reduce 的回报?

[英]How can I make a recursive Promise call to be the return for a reduce in Javascript?

I'm trying to create a recursive Promise call inside a reduce in JS.我正在尝试在 JS 的reduce中创建一个递归的Promise调用。 The goal for my system here is to make n big calls for each item in the array that reduce plays with, then, if, inside that reduce that big call decides it needs n smaller calls before it gets back to the big ones, then the reduce shouldn't skip to the next item, just wait for it to finish.我的系统的目标是对数组中的每个项目进行 n 个大调用, reduce播放,然后,如果在该reduce内部,该大调用决定它在返回大调用之前需要 n 个较小的调用,那么reduce不应该跳到下一个项目,只需等待它完成即可。

My current code is:我目前的代码是:

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.log( 'Got this error:' + error);
    });

    return import_files_download;
}

Where Base_Ajax_Requester is a helper class that handles AJAX requests and returns a Promise when it's done so code could be written around it.其中Base_Ajax_Requester是一个辅助类,它处理 AJAX 请求并在完成时返回一个Promise ,以便可以围绕它编写代码。

My fake_data is:我的fake_data是:

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

As you can see fake_data.steps_to_import.reduce(.. will go through these 3 values, for each of them call download_demo_file , wait for it to finish, then proceed to the next. We could say that I'd like to, between elementor-hf and post to have n smaller calls.如您所见, fake_data.steps_to_import.reduce(..将遍历这 3 个值,为每个值调用download_demo_file ,等待它完成,然后继续下一个。我们可以说我想,在elementor-hf之间elementor-hfpost n 个较小的调用。

The initial call to download_demo_file is seen up there, here's what will always come back from the back-end:在那里可以看到对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.
}

The retry call, again, with download_demo_file would look like:再次调用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.
}

...and so on, until the back-end sends remaining_number_of_files : 0 , then it all stops because there are no more files to download and it can skip to the next big call. ...依此类推,直到后端发送remaining_number_of_files : 0 ,然后一切都会停止,因为没有更多文件要下载,并且可以跳到下一个大调用。

How can I achieve this?我怎样才能做到这一点?

Inside each reduce callback, I'd make a function that calls download_demo_file (with a changing file_counter ), and after that Promise resolves, recursively returns a call of itself if remaining_number_of_files > 0 .在每个reduce回调中,我会创建一个调用download_demo_file的函数(带有不断变化的file_counter ),在 Promise 解析之后,如果remaining_number_of_files > 0 file_counter remaining_number_of_files > 0则递归地返回自身调用。 This will mean that getProm() will continually call itself until the remaining_number_of_files > 0 condition is not fulfilled anymore, and that only after that will the whole Promise for that particular reduce iteration resolve.这意味着getProm()将不断调用自身,直到remaining_number_of_files > 0 getProm() remaining_number_of_files > 0条件不再满足,并且只有在此之后,该特定reduce迭代的整个 Promise 才会解决。

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.log('Got this error:' + error);
});

The code would probably be a lot easier to read and understand with async / await , though:该代码可能会是一个容易阅读和理解与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?

Catch in the consumer of the async function.捕获异步函数的使用者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM