The then()
method returns a Promise
. It takes up to two arguments: callback functions for the success and failure cases of the Promise
.
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, a new Promise
is created with no additional handlers, simply adopting the final state of the original Promise
on which then
was called.
Syntax
p.then(onFulfilled[, onRejected]); p.then(function(value) { // fulfillment }, function(reason) { // rejection });
Parameters
onFulfilled
- A
Function
called if thePromise
is fulfilled. This function has one argument, thefulfillment value
. onRejected
Optional- A
Function
called if thePromise
is rejected. This function has one argument, therejection reason
.
Return value
A Promise
in the pending status. The handler function (onFulfilled
or onRejected
) gets then called asynchronously (as soon as the stack is empty). After the invocation of the handler function, if the handler function:
- returns a value, the promise returned by
then
gets resolved with the returned value as its value; - throws an error, the promise returned by
then
gets rejected with the thrown error as its value; - returns an already resolved promise, the promise returned by
then
gets resolved with that promise's value as its value; - returns an already rejected promise, the promise returned by
then
gets rejected with that promise's value as its value.
If the handler function, instead, returns another pending promise object, the resolution/rejection of the promise returned by then
will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the value of the promise returned by then
will be the same as the 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 var resolvedProm = Promise.resolve(33); var thenProm = resolvedProm.then(function(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(function(){ 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 ("Error!"); } ); p1.then( value => { console.log(value); // Success! }, reason => { console.log(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 return the unworked on // string to the next then .then(function(string) { setTimeout(function() { string += 'baz'; console.log(string); }, 1) return string; }) // 3. print helpful messages about how the code in this section will be run // before string is actually processed by the mocked asynchronous code in the // prior 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); });
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 + '- This synchronous usage is virtually pointless'); // 2- This synchronous usage is virtually pointless }); 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 'Oh no!'; }) .then( () => { console.log( 'Not called.' ); }, reason => { console.error( 'onRejected function called: ', reason ); });
In all other cases, a resolving Promise is returned. In the following example, the first then()
will return 42
wrapped 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 'Oh no!'; }) .catch( reason => { console.error( 'onRejected function called: ', reason ); }) .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(20); }, 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.log('rejected', e); }); var p3 = p1.then(function() { // Return promise here, that will be rejected with 20 after 1 second return new Promise(rejectLater); }); p3.then(function(v) { // not called console.log('resolved', v); }, function(e) { console.log('rejected', e); // "rejected", 20 });
Specifications
Specification | Status | Comment |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'Promise.prototype.then' in that specification. |
Standard | Initial definition in an ECMA standard. |
ECMAScript Latest Draft (ECMA-262) The definition of 'Promise.prototype.then' in that specification. |
Living Standard |
Browser compatibility
To contribute to this compatibility data, please write a pull request against this repository: https://github.com/mdn/browser-compat-data.
Feature | Chrome | Edge | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Basic Support | 32.0 | (Yes) | 29.0 | No | 19 | 7.1 |
Feature | Android | Chrome for Android | Edge mobile | Firefox for Android | IE mobile | Opera Android | iOS Safari |
---|---|---|---|---|---|---|---|
Basic Support | 4.4.4 | 32.0 | (Yes) | 29 | No | (Yes) | 8.0 |