The then() method returns a Promise. It takes up to two arguments: callback functions for the success and failure cases of the Promise.
The source for this interactive demo is stored in a GitHub repository. If you'd like to contribute to the interactive demo project, please clone https://github.com/mdn/interactive-examples and send us a pull request.
If one or both arguments are omitted or are provided non-functions, then then will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state (fulfillment or rejection) for which then has no handler, the returned promise simply adopts the final state of the original Promise on which then was called.
Syntax
p.then(onFulfilled[, onRejected]);
p.then(value => {
// fulfillment
}, reason => {
// rejection
});
Parameters
onFulfilledOptional- A
Functioncalled if thePromiseis fulfilled. This function has one argument, thefulfillment value. If it is not a function, it is internally replaced with an "Identity" function (it returns the received argument). onRejectedOptional- A
Functioncalled if thePromiseis rejected. This function has one argument, therejection reason. If it is not a function, it is internally replaced with a "Thrower" function (it throws an error it received as argument).
Return value
Once a Promise is fulfilled or rejected, the respective handler function (onFulfilled or onRejected) will be called asynchronously (scheduled in the current thread loop). The behavior of the handler function follows a specific set of rules. If a handler function:
- returns a value, the promise returned by
thengets resolved with the returned value as its value. - doesn't return anything, the promise returned by
thengets resolved with anundefinedvalue. - throws an error, the promise returned by
thengets rejected with the thrown error as its value. - returns an already fulfilled promise, the promise returned by
thengets fulfilled with that promise's value as its value. - returns an already rejected promise, the promise returned by
thengets rejected with that promise's value as its value. - returns another pending promise object, the resolution/rejection of the promise returned by
thenwill be subsequent to the resolution/rejection of the promise returned by the handler. Also, the resolved value of the promise returned bythenwill be the same as the resolved value of the promise returned by the handler.
Following, an example to demonstrate the asynchronicity of the then method.
// using a resolved promise, the 'then' block will be triggered instantly,
// but its handlers will be triggered asynchronously as demonstrated by the console.logs
const resolvedProm = Promise.resolve(33);
let thenProm = resolvedProm.then(value => {
console.log("this gets called after the end of the main stack. the value received and returned is: " + value);
return value;
});
// instantly logging the value of thenProm
console.log(thenProm);
// using setTimeout we can postpone the execution of a function to the moment the stack is empty
setTimeout(() => {
console.log(thenProm);
});
// logs, in order:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "this gets called after the end of the main stack. the value received and returned is: 33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}
Description
As the then and Promise.prototype.catch() methods return promises, they can be chained — an operation called composition.
Examples
Using the then method
var p1 = new Promise((resolve, reject) => {
resolve('Success!');
// or
// reject(new Error("Error!"));
});
p1.then(value => {
console.log(value); // Success!
}, reason => {
console.error(reason); // Error!
});
Chaining
The then method returns a Promise which allows for method chaining.
If the function passed as handler to then returns a Promise, an equivalent Promise will be exposed to the subsequent then in the method chain. The below snippet simulates asynchronous code with the setTimeout function.
Promise.resolve('foo')
// 1. Receive "foo", concatenate "bar" to it, and resolve that to the next then
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1);
});
})
// 2. receive "foobar", register a callback function to work on that string
// and print it to the console, but not before returning the unworked on
// string to the next then
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string); // foobarbaz
}, 1)
return string;
})
// 3. print helpful messages about how the code in this section will be run
// before the string is actually processed by the mocked asynchronous code in the
// previous then block.
.then(function(string) {
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising");
// Note that `string` will not have the 'baz' bit of it at this point. This
// is because we mocked that to happen asynchronously with a setTimeout function
console.log(string); // foobar
});
// logs, in order:
// Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising
// foobar
// foobarbaz
When a value is simply returned from within a then handler, it will effectively return Promise.resolve(<value returned by whichever handler was called>).
var p2 = new Promise(function(resolve, reject) {
resolve(1);
});
p2.then(function(value) {
console.log(value); // 1
return value + 1;
}).then(function(value) {
console.log(value + ' - A synchronous value works'); // 2 - A synchronous value works
});
p2.then(function(value) {
console.log(value); // 1
});
A then call will return a rejected promise if the function throws an error or returns a rejected Promise.
Promise.resolve()
.then(() => {
// Makes .then() return a rejected promise
throw new Error('Oh no!');
})
.then(() => {
console.log('Not called.');
}, error => {
console.error('onRejected function called: ' + error.message);
});
In all other cases, a resolving Promise is returned. In the following example, the first then() will return 42 wrapped in a resolving Promise even though the previous Promise in the chain was rejected.
Promise.reject()
.then(() => 99, () => 42) // onRejected returns 42 which is wrapped in a resolving Promise
.then(solution => console.log('Resolved with ' + solution)); // Resolved with 42
In practice, it is often desirable to catch rejected promises rather than use then's two case syntax, as demonstrated below.
Promise.resolve()
.then(() => {
// Makes .then() return a rejected promise
throw new Error('Oh no!');
})
.catch(error => {
console.error('onRejected function called: ' + error.message);
})
.then(() => {
console.log("I am always called even if the prior then's promise rejects");
});
You can also use chaining to implement one function with a Promise-based API on top of another such function.
function fetch_current_data() {
// The fetch() API returns a Promise. This function
// exposes a similar API, except the fulfillment
// value of this function's Promise has had more
// work done on it.
return fetch('current-data.json').then(response => {
if (response.headers.get('content-type') != 'application/json') {
throw new TypeError();
}
var j = response.json();
// maybe do something with j
return j; // fulfillment value given to user of
// fetch_current_data().then()
});
}
If onFulfilled returns a promise, the return value of then will be resolved/rejected by the promise.
function resolveLater(resolve, reject) {
setTimeout(function() {
resolve(10);
}, 1000);
}
function rejectLater(resolve, reject) {
setTimeout(function() {
reject(new Error('Error'));
}, 1000);
}
var p1 = Promise.resolve('foo');
var p2 = p1.then(function() {
// Return promise here, that will be resolved to 10 after 1 second
return new Promise(resolveLater);
});
p2.then(function(v) {
console.log('resolved', v); // "resolved", 10
}, function(e) {
// not called
console.error('rejected', e);
});
var p3 = p1.then(function() {
// Return promise here, that will be rejected with 'Error' after 1 second
return new Promise(rejectLater);
});
p3.then(function(v) {
// not called
console.log('resolved', v);
}, function(e) {
console.error('rejected', e); // "rejected", 'Error'
});
window.setImmediate style promise-based polyfill
Using a Function.prototype.bind() Reflect.apply (Reflect.apply()) method to create a (non-cancellable) window.setImmediate-style function.
const nextTick = (() => {
const noop = () => {}; // literally
const nextTickPromise = () => Promise.resolve().then(noop);
const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args])
const nextTick = (fn, ...args) => (
fn !== undefined
? Promise.resolve(args).then(rfab(null, fn, null))
: nextTickPromise(),
undefined
);
nextTick.ntp = nextTickPromise;
return nextTick;
})();
Specifications
| Specification |
|---|
| ECMAScript (ECMA-262) The definition of 'Promise.prototype.then' in that specification. |
Browser compatibility
| Desktop | Mobile | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
then() | Chrome Full support 32 | Edge Full support 12 | Firefox Full support 29 | IE No support No | Opera Full support 19 | Safari Full support 8 | WebView Android Full support 4.4.3 | Chrome Android Full support 32 | Firefox Android Full support 29 | Opera Android Full support 19 | Safari iOS Full support 8 | Samsung Internet Android Full support 2.0 | nodejs Full support 0.12 |
Legend
- Full support
- Full support
- No support
- No support
