Skip to content

Instantly share code, notes, and snippets.

@jish
Created October 28, 2014 22:35
Show Gist options
  • Save jish/e9bcd75e391a2b21206b to your computer and use it in GitHub Desktop.
Save jish/e9bcd75e391a2b21206b to your computer and use it in GitHub Desktop.
An example "always" behavior for ES6 promises. This only works if you do not create / return intermediate promises.
// A thing I want to do
// This flow only involves **one** promise, for example an ajax call
// None of the subsequent `then` or `catch` calls, return new promises.
var explode = false;
var promise = new Promise(function(resolve, reject) {
if (explode) {
reject();
} else {
resolve();
}
}).then(function() {
console.log('Thing is done. Do followup task.');
return 'my argument';
}).then(function(arg1) {
console.log('Thing is done. Do followup task 2. argument: ' + arg1);
}).catch(function() {
console.log('Thing failed');
}).then(function() {
console.log('Always do this');
});
// => "Thing is done. Do followup task."
// => "Thing is done. Do followup task 2. argument: my argument"
// => "Always do this"
// Set explode to true
var explode = true;
var promise = new Promise(function(resolve, reject) {
if (explode) {
reject();
} else {
resolve();
}
}).then(function() {
console.log('Thing is done. Do followup task.');
return 'my argument';
}).then(function(arg1) {
console.log('Thing is done. Do followup task 2. argument: ' + arg1);
}).catch(function() {
console.log('Thing failed');
}).then(function() {
console.log('Always do this');
});
// => "Thing failed"
// => "Always do this"
@Download
Copy link

The trick is to think of it in terms of try...catch. So this code:

someActionThatMightFail()
.then(..)
.catch(..)

is effectively equivalent to:

try {
  someActionThatMightFail()
  // code here is equivalent to `then`
}
catch() {
  // code here is equivalent to `catch`
}

Now, when you chain promises after the catch handler, like this:

someActionThatMightFail()
.then(..)
.catch(..)
.then(someOtherRiskyAction)
.catch(..)

you are effectively creating this pattern:

try {
  try {
    someActionThatMightFail()
    // code here is equivalent to the first `then`
  }
  catch() {
    // code here is equivalent to the first `catch`
  }

  // code here is equivalent to the second `then`
}
catch() {
  // code here is equivalent to the second `catch`
}

I find that when I think of it this way, it makes a lot more sense.

One other thing to keep in mind:

no return statement == return undefined == return Promise.resolve()

In other words, if your catch handler does not return, it implicitly returns undefined, which is automatically converted to Promise.resolve(). To reject, you should either return Promise.reject() or throw new Error(..).

@henkin
Copy link

henkin commented Oct 12, 2016

Thanks, y'all. That clarified some things for me.

@pennyandsean
Copy link

Thanks for this. Nice and clear.

@ArndBrugman
Copy link

Top! was looking for exactly this transition away from
.always
your to
.then(function(){}).catch(function(){}).then
is a great solution for me. Thx!

@SDemonUA
Copy link

SDemonUA commented May 8, 2018

@ArndBrugman
You can avoid .catch Identifier by using:

.then(function(){}, function(){}).then(function(){ /* this will be always */ });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment