返回其他值和承诺

时间:2020-01-24 13:14:50

标签: javascript jquery ajax promise

我有一个主要表格和多个相关的内联表格。提交主表单时,所有其他内联表单都应一起提交。

但是,如果任何内联表单失败(我们在响应中将其标记出来),则不会提供主表单。

问题是submitInlineForm返回了诺言。我们如何传递表单提交是否成功,以便我们可以在submitForm中进行处理?

let submitForm = $form => {
    let formsToSubmit = [];
    $('.form-inline').each(function () {
        const $f= $(this);
        if (submittable($f)) formsToSubmit.push(submitInlineForm($f));
    });

    $.when(formsToSubmit).done(() => {
        if (!allFormsSuccessfull) return false;  // how to determine all forms were successfull?
        $.ajax({...});
    })
};


let submitInlineForm = $form => {
    return $.ajax({
        url: $form.attr('action'),
        type: 'post',
        success: response => {
            if (response.success) {
                // ???????
                // what to do here to indicate the inline form was successfully submitted?
            } else {
                // ???????
            }
        }
    });
};

1 个答案:

答案 0 :(得分:0)

很好的问题,也许不像最初看到的那么简单。

首先,您无需返回其他值和promise。

除非出现同步错误,否则表单提交成功/失败的全部内容都由submitInlineForm()返回的诺言中传达了……。但是其中存在一些不足之处……

  • jQuery.ajax()返回的承诺不是标准的。
  • jQuery.when()Promise.all()聚合的承诺中的任何单个失败都会(没有采取措施来阻止它)导致聚合的承诺采取其错误路径。

...所以:

  • 为了计算成功和失败,您可以reflect submitInlineForm()返回的承诺,否则任何一次失败都会导致Promise.all()返回的承诺失败。
  • 为了使jqXHR成功(以一种标准方式)得到反映,您首先需要规范化jqXHR的.then()回调所暴露的多个参数。

幸运的是,有几个实用程序函数使主代码非常简单。

let reflect = (promise) => {
    return promise.then(function(v){ return {v:v, status: "fulfilled" }},
                        function(e){ return {e:e, status: "rejected" }});
};

let normalise = (jqXHR) => {
    // Recastast jqXHR as native js Promise by wrapping in `Promise.resolve()`.
    return Promise.resolve(jqXHR.then((response, textStatus, jqXHR) => {
        // this is a jQuery success handler.
        if (response.success) {
            // normalise the params into one js plain object
            return { response, textStatus, jqXHR };
        } else {
            return $.Deferred().reject(new Error('response.success was falsy')); // throw the jQuery way (not strictly necessary in jQuery v3+)
        }
    }, (jqXHR, textStatus, errorThrown) => {
        // This is a jQuery error handler.
        // Normalise the params into one js Error object.
        return $.Deferred().reject(new Error(textStatus || errorThrown)); // throw the jQuery way (not strictly necessary in jQuery v3+)
    }));
};

有了这些实用程序,主代码就非常简单。

let submitForm = () => {
    let formsToSubmit = $('.form-inline').get().filter(submittable);

    return Promise.all(formsToSubmit.map(submitInlineForm).map(normalise).map(reflect)) // Yay, the two pitfalls are overcome in a single line!
    .then(outcomes => {
        // Because all the promises in formsToSubmit were reflected, you will end up here regardless of any error(s).
        // Now separate out the successes and errors
        let successes = outcomes.filter(o => o.status === 'fulfilled').map(o => o.v.response); // array of raw ajax responses
        // let successes = outcomes.filter(o => o.status === 'fulfilled').map(o => o.v.response.values); // alternatively, you might choose to extract the data of interest fom the raw responses at this point.
        let errors = outcomes.filter(o => o.status === 'rejected').map(o => o.e); // array of errors
        if (errors.length > 0) { // were there any errors?
            return false;
        } else {
            // All forms were successfull (`successes` should be congruous with `outcomes`).
            // Do something with the successes.
            return $.ajax({...}); // or whatever
        }
    });
};

let submitInlineForm = $form => {
    return $.ajax({
        'url': $form.attr('action'),
        'type': 'post'
    });
};

未测试