Я выполняю несколько обещаний со следующим фрагментом:
await Promise.all([promise1, promise2, promise3]);
Чего я хотел бы добиться, так это отменить последствия успешных промисов в случае отказа от Promise.all()
.
Говоря более конкретно, это означает, что описанное выше будет выполнять шифрование некоторых файлов, но если один из них не удастся, я хотел бы удалить другие два (или один) файла, которые были успешно зашифрованы, чтобы иметь согласованные и чистые группы файлов.
Из того, что я прочитал, это означает, что мне понадобятся два шага:
1. Отлавливать ошибки для каждого промиса, чтобы Promise.all()
не выдавал ошибку.
2. Загадочная часть: иметь еще один вид Promise.all()
:
await Promise.all([rollbackPromise1, rollbackPromise2, rollbackPromise3]);
Это кажется сложной частью: должен ли я выполнять все откаты независимо от невыполненного обещания? Это означает, что я должен делать еще один перехват для каждой ошибки, чтобы Promise.all()
ждал завершения каждого отката.
Это лучший способ сделать это, я считаю его довольно неэффективным и уродливым с точки зрения кода.
Вы можете создать наивное решение следующим образом:
const errorHandlers = []
function enc1 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('str')
}, 1000)
errorHandlers.push(() => {
console.log('handler 1')
})
})
}
function enc2 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('str')
}, 2000)
errorHandlers.push(() => {
console.log('handler 2')
})
})
}
function enc3 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('str')
}, 3000)
errorHandlers.push(() => {
console.log('handler 3')
})
})
}
Promise.all([enc1(), enc2(), enc3()]).then(() => {
console.log('all resovled')
}).catch((e) => {
errorHandlers.forEach(handler => handler(e))
})
Это даст вам возможность обрабатывать «глобальную» ошибку в каждом промисе. Перед созданием обещания всех вы можете сбросить обработчики ошибок, чтобы предотвратить многократное выполнение обработчиков ошибок.
"Если я не ошибаюсь"
Вы можете создать собственную функцию, реализующую асинхронный вызов функций и выполняющую откат при необходимости.
// Function that'll perform a promise.all and rollback if required
async function allWithRollback(promises) {
// using the map we are going to wrap the promise inside of a new one
return Promise.all(promises.map(([
func,
rollbackFunc,
], xi) => ((async() => {
try {
await func;
console.log('One Function succeed', xi);
} catch (err) {
console.log('One Function failed, require rollback', xi);
await rollbackFunc();
}
})())));
}
// Call the custom Promise.all
allWithRollback([
[
// First param is the promise
okPromise(),
// Second param is the rollback function to execute
() => {},
],
[okPromise(), () => {}],
[errPromise(), rollback1],
[errPromise(), rollback2],
[okPromise(), () => {}],
]);
// ---------
async function okPromise() {
return true;
}
async function errPromise() {
throw new Error('no one read this');
}
async function rollback1() {
console.log('Performed the rollback1');
}
async function rollback2() {
console.log('Performed the rollback2');
}
Я предполагаю, что для rollback
-s тоже будут okPromise()
-s, если я правильно понимаю. Имеет смысл. Разумна ли такая логика (та, которую я использовал с откатами) при решении подобных проблем? Потому что у функций отката могут быть свои собственные сбои, поэтому нет никакого способа реально гарантировать выполнение. Есть ли смысл это делать, или это надо оставить делать вручную, и просто заметить как лог ошибок. Потому что позже у меня будет гораздо больше выполнений, которые могут завершиться неудачно, и включение откатов во все предыдущие откаты кажется немного излишним.
Да, у okPromise()
тоже есть свой откат. Добавление автоматического отката может быть целесообразным в зависимости от проблемы. Некоторые проблемы «ожидаются», и вам нужно с ними справиться. Когда это неожиданно, журнал и ручное лечение кажутся уместными. Все дело в контексте. Часто ли бывают ошибки? Насколько важным может быть ошибка? Должна ли доступность моей системы составлять 99,99%? Моя база данных будет повреждена в случае отсутствия отката?
Я думаю, что этот, я не ошибаюсь, не ждет выполнения других обещаний, как только одно терпит неудачу. Это будет означать, что обработчики ошибок могут начать выполняться в нестабильном состоянии до того, как завершится выполнение соответствующего промиса, независимо от того, произошел сбой или нет.