Хороший вопрос, и, возможно, не такой простой, как кажется на первый взгляд.
Во-первых, вам не нужно возвращать дополнительные значения вместе с обещанием.
Запрет на синхронные ошибки, полностью об успехе / неудаче отправки формы передается в обещании, возвращаемом submitInlineForm()
.... но в этом есть ошибки ...
- обещания, возвращаемые
jQuery.ajax()
, не являются стандартными. - Любой отдельный сбой в наборе обещаний, агрегированных с
jQuery.when()
или Promise.all()
, приведет (без мер по предотвращению) к агрегированному обещанию, выбравшему путь ошибки.
... так:
- для подсчета успехов и неудач вы можете отразить обещания, возвращенные
submitInlineForm()
, в противном случае любой отдельный сбой вызовет обещание, возвращенное Promise.all()
сбой. - Для успешного отражения jqXHR (стандартным способом) необходимо сначала нормализовать множественные параметры, подвергаемые обратным вызовам
.then()
jqXHR.
К счастью, пара служебных функций позволяет основному коду быть довольно простым.
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'
});
};
не проверено