async/await、Promise执行顺序

2019-1-7    分类: 前端资源

这个有点难懂,需要一些基础知识来支持。

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”