一、promise本身是同步还是异步呢?
众所周知,Promise是ES6提出的解决异步编程导致陷入回调地狱问题的,那么Promise是同步的还是异步的?可以确定的是,Promise本身是同步的,而他的.then和.catch为异步的。 举个栗子: console.log(1) let a = new Promise((res,rej) => { console.log(2); }); console.log(3); let b = new Promise((res,rej) => { console.log(4); }); console.log(5); //1,2,3,4,5
二、返回的异步代码执行顺序 (.then / .catah)
console.log(1) let a = new Promise((res,rej) => { console.log(2); res(); }); console.log(3); let b = new Promise((res,rej) => { console.log(4); res(); }); console.log(5); a.then(() => { //先执行a,是因为.then是一个微任务,而且a最先进入微任务队列,所以现在执行a,在执行b,但都必须是在等到同步代码结束之后在进入执行队列; console.log(6) }) b.then(() => { console.log(7) })栗子:
promise1
promise2
1
4
2
5
3
6
三、宏任务与微任务
- JS是一种单线程语言,代码执行顺序(同步代码先执行---->等同步代码执行完毕异步代码在执行)主线任务清空之后,异步进入任务队列,开始从任务队列进入到主线程。 - 异步任务里面又存在宏任务和微任务。(同步代码不存在宏任务与微任务一说) - 宏任务:定时器 / **script**。 - 微任务:.then
<script> console.log('start'); //同步 setTimeout(()=>{ //宏任务 console.log('time1'); }) new Promise((resolve)=>{ console.log('promise'); //同步 resolve(); }) .then(()=>{ //.then是异步 微任务 console.log('then'); }) setTimeout(()=>{ // 宏任务 console.log('time2'); }) console.log('外部console'); //同步 </script> 执行顺序: 1、首先同步代码先依次执行; star,promise 外部console 2、then,第一个宏任务下的微任务, 3、time1 time2 宏任务
注意:在下一个宏任务开始之前,必须将当前主线微任务全部执行完毕,才进入下一个宏任务,也就是所谓的事件循环---eventloop。
三、async和await函数
async 函数是什么?一句话,它就是 Generator 函数的语法糖,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。
async
函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then
方法指定下一步的操作。
进一步说,async
函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await
命令就是内部then
命令的语法糖。
注意,await之后的代码必须等await语句执行完成后(包括微任务完成),才能执行后面的,也就是说,只有运行完await语句,才把await语句后面的全部代码加入到微任务行列,所以,在遇到await promise时,必须等await promise函数执行完毕才能对await语句后面的全部代码加入到微任务中,所以, 在等待await Promise.then微任务时, 1.运行其他同步代码, 2.等到同步代码运行完,开始运行await promise.then微任务, 3.await promise.then微任务完成后,把await语句后面的全部代码加入到微任务行列, 4.根据微任务队列,先进后出执行微任
console.log(1) async function async1(){ console.log('async1 start') await async2() //在此先做返回,将后面所有的代码放到异步队列, console.log('async1 end') } async function async2(){ console.log('async2') } async1(); console.log('i am koala')//结果:
1
async1 start
async2
i am koala
async1 end
async 函数返回一个 Promise 对象,(promise 本身为同步代码)
async function t1() { console.log(1) console.log(2) await new Promise(resolve => { setTimeout(() => { console.log('t1p') resolve() }, 5000) }) await console.log(3) console.log(4) } async function t2() { console.log(5) console.log(6) await Promise.resolve().then(() => console.log('t2p')) console.log(7) console.log(8) } t1() t2() console.log('end')
1
2
5
6
end
t2p
7
8
t1p
3
4
async function async1() { console.log( 'async1 start' ) await async2() console.log( 'async1 end' ) } async function async2() { console.log( 'async2' ) } console.log( 'script start' ) //属于一个同步代码,优先于async返回的promise执行,在async内部! setTimeout( function () { console.log( 'setTimeout' ) }, 0 ) async1(); new Promise( function ( resolve ) { console.log( 'promise1' ) resolve(); } ).then( function () { console.log( 'promise2' ) } ) console.log( 'script end' )//执行结果
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
async function t1 () { console.log(1) //1 console.log(2) //2 new Promise( function ( resolve ) { console.log( 'promise3' ) //3 resolve(); } ).then( function () { console.log( 'promise4' ) } ) await new Promise( function ( resolve ) { //如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码, //等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果 console.log( 'b' ) //4 resolve(); } ).then( function () { console.log( 't1p' ) } ) console.log(3) console.log(4) new Promise( function ( resolve ) { console.log( 'promise5' ) resolve(); } ).then( function () { console.log( 'promise6' ) } ) } setTimeout( function () { console.log( 'setTimeout' ) }, 0 ) async function t2() { console.log(5) console.log(6) await Promise.resolve().then(() => console.log('t2p')) //属于promise方法,不是对象! console.log(7) console.log(8) } t1() new Promise( function ( resolve ) { console.log( 'promise1' ) //同步代码 resolve(); } ).then( function () { console.log( 'promise2' ) } ) t2() console.log('end');//执行结果;
1
2
promise3
b
promise1
5
6
end
promise4
t1p
promise2
t2p
3
4
promise5
7
8
promise6
setTimeout
分析:
当遇见第一个await之后,阻止后面的承誉德执行,加入微任务队列;执行其他同步代码,但是5,6先于end之前执行,是因为t2在end之前调用。
总结:await后面如果等到的是promise对象,执行完resolve之后,阻止后面程序的运行,加入微任务队列,如果是promise方法,也就是不是promise对象的时候,同样也阻止后面的程序的运行,也加入微任务队列。
要有最平凡的生活,和最遥远的梦想,即使明天天寒地冻,路遥马亡……