Tengo promesas encadenadas manejadas por un bloque catch.
Si una de las promesas se rechaza, quiero hacer la limpieza en el bloque catch según el paso que falló.
Sin embargo, la limpieza en sí misma también devuelve una Promesa que debe cumplirse antes de que finalmente pueda rechazar la función.
El problema es: ¿Qué pasa si mi promesa de limpieza no se resuelve? ¿Esto no causaría un bucle de .then & .catch? ¿Cómo puedo asegurarme de que mi limpieza se ejecute antes de finalizar la función?
Ejemplo:
return promise1() .then(() => promise2) .then(() => promise3) .then(() => { return { result: xyz } } .catch((error) => { return cleanup() .then(() => { throw(error) } }Personalmente, solo usaría la sintaxis async / await . Esto permite un control más simple de las esperas y los valores de resolución/rechazo.
const myAsyncFun = async () => { try { await promise1() await promise2 await promise3 return { result: "xyz" } } catch (error) { try { await cleanup() } catch (cleanupError) { // handle cleanup error } finally { throw error // reject with the original error } } }Respuesta original a continuación...
Parece que quieres usar Promise.prototype.finally()
Cuando se liquida la promesa, es decir, se cumple o se rechaza , se ejecuta la función de devolución de llamada especificada.
.catch(error => cleanup() .catch(cleanupErr => { // handle cleanup error here }) .finally(() => Promise.reject(error)) ) Esto asegurará que el resultado sea una promesa rechazada (rechazar con error ) ya sea que cleanup() se resuelva o no.
Manifestación
const cleanup = (fail) => !fail ? Promise.resolve("cleanup good") : Promise.reject("cleanup bad") const go = (failMain, failCleanup) => { const p = !failMain ? Promise.resolve("main good") : Promise.reject("main bad") return p.then(() => ({ result: "xyz" })) .catch(error => cleanup(failCleanup) .catch(cleanupErr => { // handle cleanup error here console.warn(cleanupErr) }) .finally(() => Promise.reject(error)) ) } (async () => { console.info("No errors") await go(false, false).then(console.log, console.error) console.info("Main error only") await go(true, false).then(console.log, console.error) console.info("Main and cleanup errors") await go(true, true).then(console.log, console.error) })()A tu primera pregunta: ¡No! Una vez que su programa está en el bloque catch, no tiene nada que ver con las promesas que contiene, por lo que no detectará cleanup() .
A su segunda pregunta: por supuesto, puede escribir otro bloque catch para él y arrojar un error con un mensaje de error relevante (por ejemplo, "No se pudo ejecutar la limpieza")
Eres bueno para ir.
Su código actual esperará la función de cleanup correctamente, porque devolver una promesa de una devolución de llamada en cadena ( then , catch , finally ) hace que tanto la resolución como el rechazo se propaguen correctamente.
Incluso si la función de cleanup fallara, no causaría ningún problema; el rechazo se propagaría a la promesa más externa (devuelta), y el código de la persona que llama podría detectarlo de la misma manera que una falla de las funciones de la promise1 , la promise2 o la promise3 .