When Is .Then(Success, Fail) Considered an Antipattern For Promises

JavaScript Promise: Reject handler vs catch

The difference is that if an error occurs inside resolveHandler it won't be handled by the rejectHandler, that one only handles rejections in the original promise.

The rejectHandler is not used in combination with catch that much, because most of the time we only care about that something went wrong.

Creating only one errorhandler makes the code easier to reason about.

If a specific promise in the chain should handled differently that can be a reason to use a rejectHandler, but i'd probably write a catch().then().catch() in that case.

Wait until all promises complete even if some rejected

Benjamin's answer offers a great abstraction for solving this issue, but I was hoping for a less abstracted solution. The explicit way to to resolve this issue is to simply call .catch on the internal promises, and return the error from their callback.

let a = new Promise((res, rej) => res('Resolved!')),
b = new Promise((res, rej) => rej('Rejected!')),
c = a.catch(e => { console.log('"a" failed.'); return e; }),
d = b.catch(e => { console.log('"b" failed.'); return e; });

Promise.all([c, d])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));

Promise.all([a.catch(e => e), b.catch(e => e)])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));

Taking this one step further, you could write a generic catch handler that looks like this:

const catchHandler = error => ({ payload: error, resolved: false });

then you can do

> Promise.all([a, b].map(promise => promise.catch(catchHandler))
.then(results => console.log(results))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!', { payload: Promise, resolved: false } ]

The problem with this is that the caught values will have a different interface than the non-caught values, so to clean this up you might do something like:

const successHandler = result => ({ payload: result, resolved: true });

So now you can do this:

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

Then to keep it DRY, you get to Benjamin's answer:

const reflect = promise => promise
.then(successHandler)
.catch(catchHander)

where it now looks like

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

The benefits of the second solution are that its abstracted and DRY. The downside is you have more code, and you have to remember to reflect all your promises to make things consistent.

I would characterize my solution as explicit and KISS, but indeed less robust. The interface doesn't guarantee that you know exactly whether the promise succeeded or failed.

For example you might have this:

const a = Promise.resolve(new Error('Not beaking, just bad'));
const b = Promise.reject(new Error('This actually didnt work'));

This won't get caught by a.catch, so

> Promise.all([a, b].map(promise => promise.catch(e => e))
.then(results => console.log(results))
< [ Error, Error ]

There's no way to tell which one was fatal and which was wasn't. If that's important then you're going to want to enforce and interface that tracks whether it was successful or not (which reflect does).

If you just want to handle errors gracefully, then you can just treat errors as undefined values:

> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
.then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))
< [ 'Resolved!' ]

In my case, I don't need to know the error or how it failed--I just care whether I have the value or not. I'll let the function that generates the promise worry about logging the specific error.

const apiMethod = () => fetch()
.catch(error => {
console.log(error.message);
throw error;
});

That way, the rest of the application can ignore its error if it wants, and treat it as an undefined value if it wants.

I want my high level functions to fail safely and not worry about the details on why its dependencies failed, and I also prefer KISS to DRY when I have to make that tradeoff--which is ultimately why I opted to not use reflect.

Resolve promises one after another (i.e. in sequence)?

Update 2017: I would use an async function if the environment supports it:

async function readFiles(files) {
for(const file of files) {
await readFile(file);
}
};

If you'd like, you can defer reading the files until you need them using an async generator (if your environment supports it):

async function* readFiles(files) {
for(const file of files) {
yield await readFile(file);
}
};

Update: In second thought - I might use a for loop instead:

var readFiles = function(files) {
var p = Promise.resolve(); // Q() in q

files.forEach(file =>
p = p.then(() => readFile(file));
);
return p;
};

Or more compactly, with reduce:

var readFiles = function(files) {
return files.reduce((p, file) => {
return p.then(() => readFile(file));
}, Promise.resolve()); // initial
};

In other promise libraries (like when and Bluebird) you have utility methods for this.

For example, Bluebird would be:

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));

var readAll = Promise.resolve(files).map(fs.readFileAsync,{concurrency: 1 });
// if the order matters, you can use Promise.each instead and omit concurrency param

readAll.then(function(allFileContents){
// do stuff to read files.
});

Although there is really no reason not to use async await today.

When to use promise.all()?

I'm not sure anyone has really given the most general purpose explanation for when to use Promise.all() (and when not to use it):

What is(are) the correct scenario(s) to use promise.all()

Promise.all() is useful anytime you have more than one promise and your code wants to know when all the operations that those promises represent have finished successfully. It does not matter what the individual async operations are. If they are async, are represented by promises and your code wants to know when they have all completed successfully, then Promise.all() is built to do exactly that.

For example, suppose you need to gather information from three separate remote API calls and when you have the results from all three API calls, you then need to run some further code using all three results. That situation would be perfect for Promise.all(). You could so something like this:

Promise.all([apiRequest(...), apiRequest(...), apiRequest(...)]).then(function(results) {
// API results in the results array here
// processing can continue using the results of all three API requests
}, function(err) {
// an error occurred, process the error here
});

Promise.all() is probably most commonly used with similar types of requests (as in the above example), but there is no reason that it needs to be. If you had a different case where you needed to make a remote API request, read a local file and read a local temperature probe and then when you had data from all three async operations, you wanted to then do some processing with the data from all three, you would again use Promise.all():

Promise.all([apiRequest(...), fs.promises.readFile(...), readTemperature(...)]).then(function(results) {
// all results in the results array here
// processing can continue using the results of all three async operations
}, function(err) {
// an error occurred, process the error here
});

On the flip side, if you don't need to coordinate among them and can just handle each async operation individually, then you don't need Promise.all(). You can just fire each of your separate async operations with their own .then() handlers and no coordination between them is needed.

In addition Promise.all() has what is called a "fast fail" implementation. It returns a master promise that will reject as soon as the first promise you passed it rejects or it will resolve when all the promises have resolved. So, to use Promise.all() that type of implementation needs to work for your situation. There are other situations where you want to run multiple async operations and you need all the results, even if some of them failed. Promise.all() will not do that for you directly. Instead, you would likely use something like Promise.settle() for that situation. You can see an implementation of .settle() here which gives you access to all the results, even if some failed. This is particularly useful when you expect that some operations might fail and you have a useful task to pursue with the results from whatever operations succeeded or you want to examine the failure reasons for all the operations that failed to make decisions based on that.

Are there any best practices to use promise.all()? Should it be
ideally used only if all of the promise objects are of the same or
similar types?

As explained above, it does not matter what the individual async operations are or if they are the same type. It only matters whether your code needs to coordinate them and know when they all succeed.


It's also useful to list some situations when you would not use Promise.all():

  1. When you only have one async operation. With only one operation, you can just use a .then() handler on the one promise and there is no reason for Promise.all().
  2. When you don't need to coordinate among multiple async operations.
  3. When a fast fail implementation is not appropriate. If you need all results, even if some fail, then Promise.all() will not do that by itself. You will probably want something like Promise.allSettled() instead.
  4. If your async operations do not all return promises, Promise.all() cannot track an async operation that is not managed through a promise.

How do I access previous promise results in a .then() chain?

ECMAScript Harmony

Of course, this problem was recognized by the language designers as well. They did a lot of work and the async functions proposal finally made it into

ECMAScript 8

You don't need a single then invocation or callback function anymore, as in an asynchronous function (that returns a promise when being called) you can simply wait for promises to resolve directly. It also features arbitrary control structures like conditions, loops and try-catch-clauses, but for the sake of convenience we don't need them here:

async function getExample() {
var resultA = await promiseA(…);
// some processing
var resultB = await promiseB(…);
// more processing
return // something using both resultA and resultB
}

ECMAScript 6

While we were waiting for ES8, we already did use a very similar kind of syntax. ES6 came with generator functions, which allow breaking the execution apart in pieces at arbitrarily placed yield keywords. Those slices can be run after each other, independently, even asynchronously - and that's just what we do when we want to wait for a promise resolution before running the next step.

There are dedicated libraries (like co or task.js), but also many promise libraries have helper functions (Q, Bluebird, when, …) that do this async step-by-step execution for you when you give them a generator function that yields promises.

var getExample = Promise.coroutine(function* () {
// ^^^^^^^^^^^^^^^^^ Bluebird syntax
var resultA = yield promiseA(…);
// some processing
var resultB = yield promiseB(…);
// more processing
return // something using both resultA and resultB
});

This did work in Node.js since version 4.0, also a few browsers (or their dev editions) did support generator syntax relatively early.

ECMAScript 5

However, if you want/need to be backward-compatible you cannot use those without a transpiler. Both generator functions and async functions are supported by the current tooling, see for example the documentation of Babel on generators and async functions.

And then, there are also many other compile-to-JS languages
that are dedicated to easing asynchronous programming. They usually use a syntax similar to await, (e.g. Iced CoffeeScript), but there are also others that feature a Haskell-like do-notation (e.g. LatteJs, monadic, PureScript or LispyScript).

Fetch: reject promise and catch the error if status is not OK?

Fetch promises only reject with a TypeError when a network error occurs. Since 4xx and 5xx responses aren't network errors, there's nothing to catch. You'll need to throw an error yourself to use Promise#catch.

A fetch Response conveniently supplies an ok , which tells you whether the request succeeded. Something like this should do the trick:

fetch(url).then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});

Node.js Best Practice Exception Handling

Update: Joyent now has their own guide. The following information is more of a summary:

Safely "throwing" errors

Ideally we'd like to avoid uncaught errors as much as possible, as such, instead of literally throwing the error, we can instead safely "throw" the error using one of the following methods depending on our code architecture:

  • For synchronous code, if an error happens, return the error:

    // Define divider as a syncrhonous function
    var divideSync = function(x,y) {
    // if error condition?
    if ( y === 0 ) {
    // "throw" the error safely by returning it
    return new Error("Can't divide by zero")
    }
    else {
    // no error occured, continue on
    return x/y
    }
    }

    // Divide 4/2
    var result = divideSync(4,2)
    // did an error occur?
    if ( result instanceof Error ) {
    // handle the error safely
    console.log('4/2=err', result)
    }
    else {
    // no error occured, continue on
    console.log('4/2='+result)
    }

    // Divide 4/0
    result = divideSync(4,0)
    // did an error occur?
    if ( result instanceof Error ) {
    // handle the error safely
    console.log('4/0=err', result)
    }
    else {
    // no error occured, continue on
    console.log('4/0='+result)
    }
  • For callback-based (ie. asynchronous) code, the first argument of the callback is err, if an error happens err is the error, if an error doesn't happen then err is null. Any other arguments follow the err argument:

    var divide = function(x,y,next) {
    // if error condition?
    if ( y === 0 ) {
    // "throw" the error safely by calling the completion callback
    // with the first argument being the error
    next(new Error("Can't divide by zero"))
    }
    else {
    // no error occured, continue on
    next(null, x/y)
    }
    }

    divide(4,2,function(err,result){
    // did an error occur?
    if ( err ) {
    // handle the error safely
    console.log('4/2=err', err)
    }
    else {
    // no error occured, continue on
    console.log('4/2='+result)
    }
    })

    divide(4,0,function(err,result){
    // did an error occur?
    if ( err ) {
    // handle the error safely
    console.log('4/0=err', err)
    }
    else {
    // no error occured, continue on
    console.log('4/0='+result)
    }
    })
  • For eventful code, where the error may happen anywhere, instead of throwing the error, fire the error event instead:

    // Definite our Divider Event Emitter
    var events = require('events')
    var Divider = function(){
    events.EventEmitter.call(this)
    }
    require('util').inherits(Divider, events.EventEmitter)

    // Add the divide function
    Divider.prototype.divide = function(x,y){
    // if error condition?
    if ( y === 0 ) {
    // "throw" the error safely by emitting it
    var err = new Error("Can't divide by zero")
    this.emit('error', err)
    }
    else {
    // no error occured, continue on
    this.emit('divided', x, y, x/y)
    }

    // Chain
    return this;
    }

    // Create our divider and listen for errors
    var divider = new Divider()
    divider.on('error', function(err){
    // handle the error safely
    console.log(err)
    })
    divider.on('divided', function(x,y,result){
    console.log(x+'/'+y+'='+result)
    })

    // Divide
    divider.divide(4,2).divide(4,0)

Safely "catching" errors

Sometimes though, there may still be code that throws an error somewhere which can lead to an uncaught exception and a potential crash of our application if we don't catch it safely. Depending on our code architecture we can use one of the following methods to catch it:

  • When we know where the error is occurring, we can wrap that section in a node.js domain

    var d = require('domain').create()
    d.on('error', function(err){
    // handle the error safely
    console.log(err)
    })

    // catch the uncaught errors in this asynchronous or synchronous code block
    d.run(function(){
    // the asynchronous or synchronous code that we want to catch thrown errors on
    var err = new Error('example')
    throw err
    })
  • If we know where the error is occurring is synchronous code, and for whatever reason can't use domains (perhaps old version of node), we can use the try catch statement:

    // catch the uncaught errors in this synchronous code block
    // try catch statements only work on synchronous code
    try {
    // the synchronous code that we want to catch thrown errors on
    var err = new Error('example')
    throw err
    } catch (err) {
    // handle the error safely
    console.log(err)
    }

    However, be careful not to use try...catch in asynchronous code, as an asynchronously thrown error will not be caught:

    try {
    setTimeout(function(){
    var err = new Error('example')
    throw err
    }, 1000)
    }
    catch (err) {
    // Example error won't be caught here... crashing our app
    // hence the need for domains
    }

    If you do want to work with try..catch in conjunction with asynchronous code, when running Node 7.4 or higher you can use async/await natively to write your asynchronous functions.

    Another thing to be careful about with try...catch is the risk of wrapping your completion callback inside the try statement like so:

    var divide = function(x,y,next) {
    // if error condition?
    if ( y === 0 ) {
    // "throw" the error safely by calling the completion callback
    // with the first argument being the error
    next(new Error("Can't divide by zero"))
    }
    else {
    // no error occured, continue on
    next(null, x/y)
    }
    }

    var continueElsewhere = function(err, result){
    throw new Error('elsewhere has failed')
    }

    try {
    divide(4, 2, continueElsewhere)
    // ^ the execution of divide, and the execution of
    // continueElsewhere will be inside the try statement
    }
    catch (err) {
    console.log(err.stack)
    // ^ will output the "unexpected" result of: elsewhere has failed
    }

    This gotcha is very easy to do as your code becomes more complex. As such, it is best to either use domains or to return errors to avoid (1) uncaught exceptions in asynchronous code (2) the try catch catching execution that you don't want it to. In languages that allow for proper threading instead of JavaScript's asynchronous event-machine style, this is less of an issue.

  • Finally, in the case where an uncaught error happens in a place that wasn't wrapped in a domain or a try catch statement, we can make our application not crash by using the uncaughtException listener (however doing so can put the application in an unknown state):

    // catch the uncaught errors that weren't wrapped in a domain or try catch statement
    // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
    process.on('uncaughtException', function(err) {
    // handle the error safely
    console.log(err)
    })

    // the asynchronous or synchronous code that emits the otherwise uncaught error
    var err = new Error('example')
    throw err

jQuery: Return data after ajax call success

The only way to return the data from the function would be to make a synchronous call instead of an asynchronous call, but that would freeze up the browser while it's waiting for the response.

You can pass in a callback function that handles the result:

function testAjax(handleData) {
$.ajax({
url:"getvalue.php",
success:function(data) {
handleData(data);
}
});
}

Call it like this:

testAjax(function(output){
// here you use the output
});
// Note: the call won't wait for the result,
// so it will continue with the code here while waiting.

How do I know which handlers throw error in promise?

everyone! I had researched demonstrated code by myself.

I hoped everyone can review my answer, it's good or not.


Introduction:

It shows how to trace promise in each handler, used customized error handler to catch error. To understand the workflow of promise.

You can copy the following demonstrated code and paste in your node.js. According to the example and log message, it's good for the developers to learn promise.


The used promise module is as following:

  • bluebird

The demonstrated code is as following:

var Promise = require('bluebird');

// You can input any argument in this function to test workflow of promise
function testPromise(input) {
let promise = Promise.resolve(input);
promise
.then(makeTask('Task1'))
.then(makeTask('Task2'))
.then(makeTask('Task3'))
.catch(makeErrorPredicate('Task1'), taskLog('Task1'))
.catch(makeErrorPredicate('Task2'), taskLog('Task2'))
.catch(makeErrorPredicate('Task3'), taskLog('Task3'))
}

// define task handler functions
function makeTask(task) {
return function task1Handler(input) {
if (input === task) {
throw new Error(task)
}
return input
}
}

// custom error that it checks error message
function makeErrorPredicate(msg) {
return function taskError(err) {
var result = err.message === msg;
console.log(msg + ': ' + result)
return result;
}
}

// hint the error when the error has matched
function taskLog(msg) {
return function thelog(err) {
console.log('It\'s ' + msg)
}
}

The example:

>testPromise('Task1')
Task1: true
It's Task1

>testPromise('Task2')
Task1: false
Task2: true
It's Task2

>testPromise('Task3')
Task1: false
Task2: false
Task3: true
It's Task3

From the example above we can know:

When input is 'Task1', the route is:

firstHandler -> firstCatcher

When input is 'Task2', the route is:

firstHandler -> secondHandler -> firstCatcher -> secondCather

When input is 'Task3', the route is:

firstHandler -> secondHandler -> thirdHandler -> firstCatcher -> secondCatcher -> thirdCatcher

So, from the result above we know, we can understand the promise how to work.


If everyone is happy with this answer or not, please let me know, thanks.



Related Topics



Leave a reply



Submit