promise 与 async
一、了解js的执行过程


js一门单线程的脚本语言,它执行代码一般从上往下逐行执行。如果过程中遇到异步操作,则将该操作先挂起到任务队列中,接着继续执行同步代码。待主线程中都执行完毕,询问任务队列中任务是否完成,未完成则逐个执行,直到最终任务队列所有执行完毕。
其实在任务队列中还会区分宏任务与微任务,正如上图。
二、promise
1 2 3 4 5 6
| let a = new Promise(resolve,reject){ resolve(1) }.then(function(res){ console.log(res) }).catch(function(){ })
|
以上就是一个简单的promise对象。promise有以下几点特效:
- promise属于宏任务
- promise的构造函数是同步,而then里的是异步
- promise状态不可逆
- then或catch return出去的数值会被后面的then或者catch接受
- promise不管返回什么,都会被包装成promise对象,即使返回一个error
- then接收到的如果不是函数,会发生穿透
- promise对象resolve或者reject一个promise对象,前一个promise的状态会由后一个决定
例子一
1 2 3 4 5 6 7 8 9 10
| setTimeout(function(){ console.log(1) }) let a = new Promise(resolve,reject){ resolve() }.then(function(res){ console.log(2) }).catch(function(){ })
|
以下执行结果是先出2,再出1。setTimeout是微任务,而promise是宏任务,所以先执行了宏任务promise
例子二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| setTimeout(function(){ console.log(1) }) let a = new Promise(resolve,reject){ resolve() }.then(function(res){ setTimeout(function(){ console.log(2) }) console.log(4) }).catch(function(){ }) setTimeout(function(){ console.log(3) })
|
以上执行结果为4、 1、3、2 。首先明确promise是宏任务,setTimeout是微任务。promise外面有两个setimeout是微任务,依次被挂起。而在promise中有console4,所以最先执行宏任务出来4。接着发现promise中有微任务setimeout,也被挂起,接着执行所有的微任务也就是1、3、2出来。
例子三
1 2 3 4 5 6 7
| new Promise(function(res,rej){ console.log(1) res(2) }).then(function(res){ console.log(res) }) console.log(3)
|
以上执行结果为1、3、2 。因为promise的构造函数是同步,而then里的是异步,所以promise的构造函数也在主线程上执行出来1,接着执行外面的3,最后才执行then里面的2
例子四
1 2 3 4 5 6 7 8
| new Promise(function(res,rej){ res(2) rej(3) }).then(function(res){ console.log(res) }).catch(function(err){ console.log(err) })
|
如果在pomise中执行了res,是不会再执行catch函数的。虽然也执行了rej,但是内部会阻止其catch。因为promise的状态是不可逆的。
例子五
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let a = new Promise(function(res,rej){ setTimeout(function(){ res(b) },1000) }) let b = new Promise(function(res,rej){ setTimeout(function(){ rej(4) },2000) }) a.then(function(){ console.log(1) }).catch(funtion(){ console.log(2) })
|
以上执行执行的结果是2。根据promise对象resolve或者reject一个promise对象,前一个promise的状态会由后一个决定。第一个promise中执行res出第二个promise对象,所以最终取决于第二个promise执行的结果。假若第一个promise并不是执行出第二个promise对象,而是直接执行出个结果,最终结果又会不一样。
三、async
async函数特点:
- async函数会返回一个promise对象
- return错误会让返回的promise对象状态为reject
- 一般来说await后面的值是一个promise
- 内部如果await多个promise对象,则会等所有promise完成后再执行then
例子一
1 2 3 4 5 6 7 8 9 10 11 12
| async function a(){ await b(); return 4 } function b(){ console.log(3) } a().then(fucntion(res){ console.log(res) })
|
以上执行的结果是3、4。在async中returen出是个promise对象,所以then的结果为4。
例子二
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| async function a(){ await b(); return new error('error...') } function b(){ console.log(3) } a().then(fucntion(res){ console.log(res) }).catch(function(err){ console.log(err) })
|
以上执行结果会返回3、和一个错误。正是async函数的第二点特性。
例子三
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| async function a(){ let c = await b(); return c } function b(){ return new Promise(function(res,rej){ res(1) }) } a().then(fucntion(res){ console.log(res) }).catch(function(err){ console.log(err) })
|
以上执行结果为1。await后面必须跟一个promise对象,才会起到异步效果,不然await只会同步执行。
例子四
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| async function a(){ let c = await b(); let e = await d(); return c+e } function b(){ return new Promise(function(res,rej){ setTimeout(function(){ res(1) },1000) }) } function d(){ return new Promise(function(res,rej){ setTimeout(function(){ res(2) },5000) }) } a().then(fucntion(res){ console.log(res) }).catch(function(err){ console.log(err) })
|
以上结果会等待5秒输出一个3。正是async函数的第四点特性,会等待所有promise对象执行完成之后输出。像这种特性,正好可以解决如果有多个接口调用,可以利用这点,解决回调嵌套问题。