简体   繁体   中英

Implementing a fail-fast design with promises in JavaScript

I'm not sure if "fail-fast" is the best way to describe this methodology, but ever since I started to learn about programming I have always been taught to design functions like this:

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
}

As such, I'm trying to call a promisified function like so:

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

But this gives me behaviour akin to the finally block of a classic try...catch...finally statement, ie the then() block will always be called, even after an error. Sometimes this is useful, but I rarely find myself needing such functionality (or try...catch statements in general, for that matter).

So in the interest of failing as quickly and clearly as possible, is there a way that I can make the second example above work in the way that I expect (ie then() is only executed if catch() wasn't, yet a single catch() will still catch all errors raised by doSomethingAsync() )?

If you use async and await instead of .then , you can effectively wait for the Promise to resolve (or reject), and if it rejects, return early:

(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'); })();

That's what I'd prefer. You can also use the .then(onResolve, onReject) technique, though it's usually not recommended :

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'); }

This will have onReject only handle errors thrown by doSomethingAsync(param) . If your onResolve can throw inside its body as well, then you'll have to chain another .catch onto it (which will start to look a bit messy - it's usually nicer to catch errors in just one place)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM