如何在递归AJAX调用中提供“解析”功能,以便可以使用“完成”?

时间:2018-11-11 12:03:34

标签: javascript promise

我正在执行一些重复的AJAX调用,其中我将一个数组从前端传递到后端,并且每当返回前端时,该数组就会变小(减1),最终它将为空,因此我的递归调用将停止。

这是我的电话:

function download_required_files(demo_data) {
    var ajaxsecurity = setup_page_params.ajax_nonce;

    jQuery.ajax({
        url: ajaxurl,
        type: 'POST',
        dataType: 'json',
        data: {
            action: 'download_import_files_request',
            security: ajaxsecurity,
            content_install_request_data: JSON.stringify(demo_data),
        },

        success: function (response) {
            console.log(response);
            var data = response.data || false;
            /**
             * If no steps are left, meaning that all required files have been downloaded, proceed with the whole install process.
             */
            if(!data.remaining_steps || !data.remaining_steps.length) {
                return false;
            }

            if(data.can_continue !== 'yes') {
                return false;
            }

            if(data.remaining_steps && data.remaining_steps.length) {
                demo_data.steps_to_take = data.remaining_steps;
                download_required_files(demo_data);

            }

            $('.demo-loader-content').fadeOut();
        },

        error: function (response) {
            $('.demo-loader-content').fadeOut();

        }
    });
}

假设我有2个步骤要下载文件,则此download_required_files将运行两次,然后将其完成,但是如果我这样做:

var download_process = download_required_files(demo_data) //Runs 2 times
download_process.done(function() {  //Do stuff here once that function ran 2 times });

它给了我Cannot read property 'done' of undefined错误,这是有充分理由的。 download_process并不是拥有该属性的承诺对象,而只是...空的。

我应该在哪里{@ {1}}进行干预,以便它向外部代码发出信号:“嘿,在应许环境中,我完成了!”

2 个答案:

答案 0 :(得分:0)

尽管对$.ajax的调用的结果是一个jqXHR对象,该对象类似于promise,对于您描述的内容,我认为我会使用您自己的本地Promise(或{{3 }}(如果您愿意)代表整个递归过程:

function download_required_files(demo_data) {
    return new Promise(function(resolve, reject) {
        function worker() {
            var ajaxsecurity = setup_page_params.ajax_nonce;

            jQuery.ajax({
                url: ajaxurl,
                type: 'POST',
                dataType: 'json',
                data: {
                    action: 'download_import_files_request',
                    security: ajaxsecurity,
                    content_install_request_data: JSON.stringify(demo_data),
                },

                success: function (response) {
                    console.log(response);
                    var data = response.data || false;
                    /**
                     * If no steps are left, meaning that all required files have been downloaded, proceed with the whole install process.
                     */
                    if(!data.remaining_steps || !data.remaining_steps.length) {
                        // *** All done
                        $('.demo-loader-content').fadeOut();
                        resolve();
                    } else if(data.can_continue !== 'yes') {
                        // *** All done; but is this an error condition? If so
                        // use `reject` instead of `resolve` below.
                        $('.demo-loader-content').fadeOut();
                        resolve();
                    } else {
                        demo_data.steps_to_take = data.remaining_steps;
                        worker();  // This is the internal recursive call
                    }
                },

                error: function (response) {
                    $('.demo-loader-content').fadeOut();

                }
            });
        }
        worker();
    });
}

或改为使用Deferred

function download_required_files(demo_data) {
    var d = $.Deferred();

    function worker() {
        var ajaxsecurity = setup_page_params.ajax_nonce;

        jQuery.ajax({
            url: ajaxurl,
            type: 'POST',
            dataType: 'json',
            data: {
                action: 'download_import_files_request',
                security: ajaxsecurity,
                content_install_request_data: JSON.stringify(demo_data),
            },

            success: function (response) {
                console.log(response);
                var data = response.data || false;
                /**
                 * If no steps are left, meaning that all required files have been downloaded, proceed with the whole install process.
                 */
                if(!data.remaining_steps || !data.remaining_steps.length) {
                    // *** All done
                    $('.demo-loader-content').fadeOut();
                    d.resolve();
                } else if(data.can_continue !== 'yes') {
                    // *** All done; but is this an error condition? If so
                    // use `d.reject` instead of `d.resolve` below.
                    $('.demo-loader-content').fadeOut();
                    d.resolve();
                } else {
                    demo_data.steps_to_take = data.remaining_steps;
                    worker();  // This is the internal recursive call
                }
            },

            error: function (response) {
                $('.demo-loader-content').fadeOut();

            }
        });
    }
    worker();
    return d.promise();
}

答案 1 :(得分:0)

这是我的方法,将单个AJAX请求与内容循环以及DOM更新分开:

function download_one_file(demo_data) {
    return jQuery.ajax({
        url: ajaxurl,
        type: 'POST',
        dataType: 'json',
        data: {
            action: 'download_import_files_request',
            security: setup_page_params.ajax_nonce,
            content_install_request_data: JSON.stringify(demo_data),
        }
    });
}

function download_loop(demo_data) {
    return download_one_file(demo_data).then(function(data) {
        if (!data) {
            return Promise.reject();
        } else if (data.remaining_steps && data.remaining_steps.length) {
            demo_data.steps_to_take = data.remaining_steps;
            return download_loop(demo_data);
        } else {
            return Promise.resolve();
        }
    });
}

function download_required_files(demo_data) {
    return download_loop(demo_data).finally(function() {
        $('.demo-loader-content').fadeOut();
    });
}