coolpasta
coolpasta

Reputation: 755

Why can't I use then on a resolved promise?

I have my function whose job is to go over a number of files (that use the values from the array as building blocks for file names) and download them using a reduce. It's more of a hack as of now but the Promise logic should work. Except it doesn.t

Here's my code:

function import_demo_files(data) {
    /**
     * Make a local copy of the passed data.
     */
    let request_data = $.extend({}, data);

    const get_number_of_files_1 = Promise.resolve({
        'data' : {
            'number_of_files' : 2
        }
    });

    return new Promise((resolve, reject) => {
        let import_files = get_number_of_files_1.then(function(response) {
            new Array(response.data.number_of_files).fill(request_data.step_name).reduce((previous_promise, next_step_identifier) => {
                let file_counter = 1;

                return previous_promise.then((response) => {
                    if( response !== undefined ) {
                        if('finished_import' in response.data && response.data.finished_import === true || response.success === false) {
                            return import_files;
                        }
                    }
                    const recursively_install_step_file = () => import_demo_file({
                        demo_handle: request_data.demo_handle,
                        'step_name': request_data.step_name,
                        'file_counter': file_counter

                    }).call().then(function(response) {
                        file_counter++;

                        if('file_counter' in response.data && 'needs_resume' in response.data) {
                            if(response.data.needs_resume === true) {
                                file_counter = response.data.file_counter;
                            }
                        }
                        return response.data.keep_importing_more_files === true ? recursively_install_step_file() : response
                    });
                    return recursively_install_step_file();
                }).catch(function(error) {
                    reject(error);
                });
            }, Promise.resolve())
        }).catch(function(error) {
            reject(error);
        });
        resolve(import_files);
    });
}

Now, when I do:

const import_call = import_demo_files({ 'demo_handle' : 'demo-2', 'step_name' : 'post' });
console.log(import_call);

The console.log gives me back that import_call is, in fact a promise and it's resolved. I very much like the way return allows me to bail out of a promise-chain, but I have no idea how to properly resolve my promise chain in there, so clearly, it's marked as resolved when it isn't.

I would like to do import_call.then(... but that doesn't work as of now, it executes this code in here before it's actually done because of the improper handling in import_demo_files.

Upvotes: 0

Views: 204

Answers (1)

Roamer-1888
Roamer-1888

Reputation: 19288

An asynchronous recursion inside a reduction isn't the simplest of things to cut your teeth on, and it's not immediately obvious why you would want to given that each iteration of the recursion is identical to every other iteration.

The reduce/recurse pattern is simpler to understand with the following pulled out, as outer members :

1. the `recursively_install_step_file()` function
1. the `new Array(...).fill(...)`, as `starterArray`
1. the object passed repeatedly to `import_demo_file()`, as `importOptions`)

This approach obviates the need for the variable file_counter, since importOptions.file_counter can be updated directly.

function import_demo_files(data) {
    // outer members
    let request_data = $.extend({}, data);
    const importOptions = {
        'demo_handle': request_data.demo_handle,
        'step_name': request_data.step_name,
        'file_counter': 1
    };
    const starterArray = new Array(2).fill(request_data.step_name);
    function recursively_install_step_file() {
        return import_demo_file(importOptions).then((res) => {
            if('file_counter' in res.data && 'needs_resume' in res.data && res.data.needs_resume) {
                importOptions.file_counter = res.data.file_counter; // should = be += ?
            } else {
                importOptions.file_counter++;
            }
            return res.data.keep_importing_more_files ? recursively_install_step_file() : res;
        });
    }

    // the reduce/recurse pattern
    return starterArray.reduce((previous_promise, next_step_identifier) => { // next_step_identifier is not used?
        let importOptions.file_counter = 1; // reset to 1 at each stage of the reduction?
        return previous_promise.then(response => {
            if(response && ('finished_import' in response.data && response.data.finished_import || !response.success)) {
                return response;
            } else {
                return recursively_install_step_file(); // execution will drop through to here on first iteration of the reduction
            }
        });
    }, Promise.resolve());
}

May not be 100% correct but the overall pattern should be about right. Be prepared to work on it some.

Upvotes: 1

Related Questions