No sé resolver esta situación usando las promesas de JS.

Imagine que tengo algunos artículos y quiero enviar una solicitud de parche para actualizarlos. Envío una solicitud por artículo. Si la solicitud de un artículo fue exitosa, entonces actualizo ese artículo, pero si la solicitud falla, entonces actualizo el artículo de manera diferente. También quiero mostrar un mensaje al usuario informando si todos los artículos se han actualizado correctamente o no.

Este no es mi escenario real y este puede ser un ejemplo extraño. Pero es lo que quiero lograr en mi aplicación React.

Esto es lo que estoy tratando de hacer en este momento:

const saveArticles = articles => {
  const promises = [];

  articles.forEach(article => {
    const promise = axios
      .patch('/articles', article)
      .then(() => updateArticleUi(article))
      .catch(() => updateArticleUiWithError(article));

    promises.push(promise);
  });

  Promise.all(promises)
    .then(() => tellTheUserThereWasNoErrors())
    .catch(() => tellTheUserThereWasSomeErrors());
};

Esto no funciona porque Promise.all siempre está ejecutando la devolución de llamada then, siempre y cuando todas las promesas tengan éxito o no.

¡Gracias!

0
Pedro Brost 10 sep. 2018 a las 17:18

4 respuestas

La mejor respuesta

Sus updateArticleUi y updateArticleUiWithErrors deben tener los valores de retorno respectivos para que pueda distinguir si hubo un error o no al mirar la matriz de resultados:

function updateArticleUi(article) {
  …
  return {success: true};
}
function updateArticleUiWithError(article, error) {
  …
  return {success: false};
}

function saveArticles(articles) {
  const promises = articles.map(article => {
    return axios.patch('/articles', article).then(() =>
      updateArticleUi(article)
    , err =>
      updateArticleUiWithError(article, err)
    );
  });

  return Promise.all(promises).then(results => 
    if (results.every(res => res.success)) {
      tellTheUserThereWasNoErrors();
    } else {
      tellTheUserThereWasSomeErrors();
    }
  });
}
1
Bergi 10 sep. 2018 a las 14:25

El problema es que está captando el error arrojado por

const promise = axios
      .patch('/articles', article)
      .then(() => updateArticleUi(article))
      .catch(() => updateArticleUiWithError(article));

Deberías lanzar un nuevo error en los axios catch() o dejar que el error brote eliminando el catch de la llamada axios.

0
Noel Kriegler 10 sep. 2018 a las 14:25

Promise.all siempre llamará entonces porque la promesa que agrega a promises ya está resuelta con then o catch adjunta arriba

Si quieres ver que catch suceda en la cadena .all simplemente lanza alguna excepción en la función updateArticleUiWithErro

0
ashish singh 10 sep. 2018 a las 14:25

Esto funciona:

function axiosPatchRequest(url,data) {
    return new Promise(function (resolve, reject) {
        if (data) {
            resolve(url);
        } else {
            reject('DATA_NOT_FOUND');
        }
    })
}

function updateArticleUi(data,article) {
    return new Promise(function (resolve, reject) {
            resolve({type:"updateArticleUi ",data,article});
        
    })
}

function updateArticleUiWithError(data,article) {
    return new Promise(function (resolve, reject) {
            reject({type:"updateArticleUiWithError ",data,article});
        
    })
}


function tellTheUserThereWasNoErrors(data){
  console.log("tellTheUserThereWasNoErrors",data);
}

function tellTheUserThereWasSomeErrors(error){
  console.log("tellTheUserThereWasSomeErrors",error);
}

const execute = (articles)=>{
  const promises = [];
articles.forEach(article => {
    const promise = axiosPatchRequest('/articles', article)
      .then((data) => {
          return updateArticleUi(data,article);
      })
      .catch((error) => {
          return updateArticleUiWithError(error,article);
          });
      promises.push(promise);
});

Promise.all(promises)
    .then((data) => tellTheUserThereWasNoErrors(data))
    .catch((error) => tellTheUserThereWasSomeErrors(error));

};

execute(["one","","three"]);
execute(["one","two","three"]);
1
Avinash 10 sep. 2018 a las 15:09