这个有点难懂,需要一些基础知识来支持。
1,Promise执行的优先级大于setTimeout/setInterval
2,async 用于申明一个 function 是异步的,所以在该function里面的程序都是异步的,但有时也需要依赖某个函数执行完成得到结果才能继续执行 ,这时候可以在函数体里面使用await
3,await 只能出现在 async 函数中
4,await后面可以接着一个直接变量或者是一个promise对象
5,await后面接着是promise对象,async函数体内就会阻塞要等await后面的promise函数执行完成才会继续往下走。async函数体外的代码可不会去一
直等待。
6,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
7,在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和直接new Promise对象效
果一样。
简单案例:
setTimeout(function (){ console.log('定时器开始啦' ) }); new Promise (function (resolve){ console.log('马上执行for循环啦'); for ( var i = 0 ; i < 10000 ; i++){ i == 99 && resolve(); } }). then (function(){ console.log( '执行then函数啦') }); console.log('代码执行结束'); 结果: 马上执行for循环啦 代码执行结束 执行then函数啦 定时器开始啦
解释:
js主线程走到setTimeout时,先把setTimeout函数扔进setTimeout队列中暂时不执行里面代码,然后js主线程代码又走到new Promise对象立马执行里面的代码,输出“马上执行for循环啦”,由于new Promise对象返回的是 Promise对象所以要扔进Promise队列中,接着js主线程接着往下走,输出“代码执行结束”,下面已经没代码可以执行了,js主线程返回查看是否有Promise队列,发现有于是执行了“执行then函数啦”,剩下已无代码可执行就把剩下的setTimeout队列里面的代码执行了输出“定时器开始啦”
直接案例:
function testSometing() { console.log("执行testSometing"); return "testSometing"; } async function testAsync() { console.log("执行testAsync"); return Promise.resolve("hello async"); } async function test() { console.log("test start..."); const v1 = await testSometing();//关键点1 console.log(v1); const v2 = await testAsync(); console.log(v2); console.log(v1, v2); } test(); var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//关键点2 promise.then((val)=> console.log(val)); console.log("test end...") 以下是执行结果: test start... 执行testSometing promise start.. test end... testSometing 执行testAsync promise hello async testSometing hello async
下面开始解释:
js主线程先是执行test()函数被调用了,执行了“test start…”,接着执行了testSometing()函数输出了“执行testSometing”,由于遇到了await,主线程跳出了test函数体外,代码接着往下走,遇到并执行了new Promise对象,输出了“promise start..”,并把new Promise对象推入到Promise队列中。代码接着往下走,遇到了“test end…”。这时候js主线程走完,开始把未执行的支线程放入到主线程中继续执行,于是就继续返回到原来跳出的test函数中那地方继续跑代码,执行到console.log(v1)输出“testSometing”,接着走到并执行testAsync函数输出“执行testAsync”,由于遇到了await,主线程再次跳出了test函数体外,代码接着往下走,发现已经没什么代码可以运行了,就把剩下的new Promise对象的then回调执行了,输出“promise”,接着回test()函数体内,由于testAsync()是new Promise对象,还要再跳出test函数,继续往下走依然没任何代码可以执行了。返回test函数体内,执行testAsync()的返回的值,console.log(v2)输出“hello async”,后面输出“testSometing hello async”。
重点注意:
1,在async函数中,遇到await后面接着是普通函数时,先把普通函数里面的代码执行了后,就会跳出async函数体外,代码接着往下跑,直到跑完
了后在重新回到await刚刚跳出的位置,继续跑async函数体内的代码。
2,在async函数中,遇到await后面接着也是async函数时也就是Promise对象,也会先执行await紧接的函数代码,之后跳出async函数体外,代码
接着往下跑,直到跑完了后在重新回到await刚刚跳出的位置,由于await后面接着是Promise对象,再次跳出async函数体外。继续跑下面的代码。
直到跑完后才再次返回到await代码处。
在来一个案例,这次加入setTimeout
async function async1() { console.log( 'async1 start' ) await async2() console.log( 'async1 end' ) } async function async2() { console.log( 'async2' ) } console.log( 'script start' ) 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
过程:
js主线程走到并输出“script start”,由于setTimeout执行的优先级低于主线程上的任务和Promise上的任务所以要等到最后,直到执行
async1()函数内,输出“async1 start”,在执行async2()函数输出“async2”,由于走到async2()函数时遇到await,要跳出async1()函
数体外,接着代码往下跑,执行new Promise对象,输出“promise1”,new Promise对象进入到Promise队列中,继续往下走,输
出“script end”,现在回到async1()函数体内中的await async2()处,由于await后面接着async2()返回的是Promise对象还要再次跳出
async1()函数体外继续执行以外的代码,这时候正好有Promise队列中的then需要执行,于是输出“promise2”,剩下没代码可以跑了,
setTimeout仍然靠后优先级低,再次回到async1()函数体内,接着执行输出“async1 end”,最后剩下主线程和Promise队列的任务都执行
完成了,就输出“setTimeout”