Реализация отказоустойчивого дизайна с обещаниями в JavaScript - PullRequest
1 голос
/ 09 января 2020

Я не уверен, что «отказоустойчивый» - лучший способ описать эту методологию, но с тех пор, как я начал изучать программирование, меня всегда учили проектировать такие функции:

function doSomething() {
    ... // do error-prone work here

    if (!allGood) {
        // Report error, cleanup and return immediately. Makes for cleaner,
        // clearer code where error-handling is easily seen at the top
        ...
        return;
    }

    // Success! Continue on with (potentially long and ugly) code that may distract from the error
}

Как таковой, я пытаюсь вызвать обещанную функцию следующим образом:

doSomethingAsync(param).catch(err => {
    console.error(err);
}).then(() => {
    // Continue on with the rest of the code
});

Но это дает мне поведение, похожее на блок finally оператора classi c try...catch...finally, т.е. блок then() будет вызываться всегда , даже после ошибки. Иногда это полезно, но я редко нахожу себя нуждающимся в такой функциональности (или, вообще говоря, try...catch заявлениях).

Так что в интересах сбоя настолько быстро и ясно, насколько это возможно, есть ли способ что я могу заставить второй пример выше работать так, как я ожидаю (то есть then() выполняется только в том случае, если catch() не было, но один catch() по-прежнему будет перехватывать все ошибки, выданные doSomethingAsync())?

1 Ответ

1 голос
/ 09 января 2020

Если вы используете async и await вместо .then, вы можете фактически дождаться разрешения (или отклонения) обещания, а если оно отклонено, вернуть досрочно:

(async () => {
  try {
    await doSomethingAsync(param);
  } catch(err) {
    console.error(err);
    return;
  }
  // Continue on with the rest of the code
})();

const doSomethingAsync = () => new Promise((resolve, reject) => Math.random() < 0.5 ? resolve() : reject('bad'));

(async () => {
  try {
    await doSomethingAsync();
  } catch(err) {
    console.error(err);
    return;
  }
  console.log('continuing');
})();

Это то, что я бы предпочел. Вы также можете использовать технику .then(onResolve, onReject), хотя она обычно не рекомендуется :

function onReject(err) {
  console.log(err);
};
doSomethingAsync(param).then(onResolve, onReject);
function onResolve() {
  // Continue on with the rest of the code
}

const doSomethingAsync = () => new Promise((resolve, reject) => Math.random() < 0.5 ? resolve() : reject('bad'));

function onReject(err) {
  console.log(err);
};
doSomethingAsync().then(onResolve, onReject);
function onResolve() {
  console.log('continuing');
}

Это будет иметь onReject только ошибок обработки, выданных doSomethingAsync(param). Если ваш onResolve также может бросить внутрь своего тела, вам придется привязать к нему еще один .catch (который начнет выглядеть немного грязно - обычно лучше ловить ошибки только в одном месте)

...