Disclaimer
This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅
Starting from a puzzle from this article:
1 | doSomething().then(function () { |
How would this code run?
To answer this puzzle, a few key points should be understood:
.then(callback) would ounly be put into the task queue when the chained promise was settled (fullfulled/resolved or rejected).
.then(callback) would pass the value returned from the callback to following .then/.catch
If there is no explicit return of the callback, returns undefined
If the callback returns a promise as well, the following .then()/.catch() would be thrown into the task queue, when it’s settled. After the current stack is cleaned, they would be pushed to the stack (run the callback). Even a promise has already settled, the .then() still runs asynchronously.
let p = Promise.resolve('resolved already') p.then(v=>{console.loe('async result: '=v)}) console.log('cleaning stack') //print 'cleaning stack' 'async result: resolved already' <!--1-->
if the callback returns a normal variable, the variable would be passed, and the state will be set to resolved.
a corner-case: if the callback returns obj which has a ‘then’ method, the following then() would run as the code in ‘then’ method.
Promise.resolve({value: 1, then: function (resolve) { //the following then call this function console.log(this.value) //print 1. resolve('then method in object') //resolve (or reject) function is a must,otherwise the following then would not be called, pending }) .then(value => { console.log('the result from pre .then:' + value); //print 'the result form pre .then: then method in object' } }) <!--2-->
But actually this is against the design of Promise whose aim is to avoid callback style but to chain the async exceutor outside the previous one. So it’d better update to this:
new Promise((resolve) => { setTimeout(() => { resolve('hello'); //the resolved value was not cusomed anywhere }, 2000); }) .then((value) => { return new Promise((resolve) => { //returning this promise!! so we can recieve the result outside! setTimeout(() => { console.log('timeout'); //2s later print 'timeout' resolve('second inner'); }, 2000); }); }) .then((v) => { //chaining this then outside console.log('closest then ' + v); //closest then second inner }); <!--3-->
If the parameter of .then is not a callback, but an invoked function (eg. foo( ), (function( ){…})( ) ). The invoked function would run immediately. And if a promise is created and resolved inside that function, it would be overseen by the chain/queue of promise.
function dosth(v) { return new Promise((resolve) => { console.log('dosth!'); resolve('something resolved'); }); } function doelse(v) { return new Promise((res) => { console.log('dosthelse!'); res('something else resolved'); }); } dosth() //sync .then(doelse()) //sync, although doelse() return a resolved promise, it didn't pass to anywhere .then((value) => { console.log(value);//async, it catches the promise from the first returned promise }); console.log('sync');//sync //print 'dosth!' 'dosthelse!' 'sync' 'something resolved' <!--4-->
For error handling, .then((res,rej)=>{…}) the parameter of rej revieve the rejected result. Or .catch(err=>{…}).
catch(err=>{..}) is basically the then(null,err=>{…})
Interestingly, the catch() returns a promise as well. If there is no explict return, it would defaultly return a resolved promise. For explicitly returning either resolved/rejected result, the following then/catch would receive the result.
new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }) .then(() => { console.log('start'); throw new Error('test error'); //return Promise.resolve('begining'); //[1] }) .catch((err) => { console.log('I catch:', err); //[1]implicit return //[2]return Promise.resolve('result from catch'); //[3]return Promise.reject('result from catch'); }) .then((v) => { console.log('arrive here ' + v); //receiving [1] v-> undefined [2] v-> 'result from catch' }) .catch((err) => { console.log('No, I catch:', err);//receiving [3] 'result from catch' }); <!--5-->
Terms:States and Fates