promise、async 、await执行顺序与js执行机制

基础定义
promise

Promise 对象是由关键字 new 及其构造函数来创建的。
该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。
这个“处理器函数”接受两个函数——resolvereject ——作为其参数。
当异步任务顺利完成且返回结果值时,会调用 resolve 函数
而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数

async

当调用一个 async 函数时,会返回一个 promise 对象
当这个异步函数返回一个值时,async 通过 Promise.resolve() 将这个值封装成 promise 对象
当这个异步函数没有返回值时,会返回 Promise.resolve(undefined)
当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值
async 函数中可能会有 await 表达式,这会使 async 函数暂停执行,等待 Promise 的结果出来,然后恢复async函数的执行并返回解析值(resolved
注意:Promise 的特点——无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致

await

await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。
语法:[return_value] = await expression; expression 是一个 Promise 对象或者任何要等待的值。返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。
若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。
若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。
另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。
注意重点:很多人以为await会一直等待之后的表达式执行完之后才会继续执行后面的代码, 实际上await是一个让出线程的标志。await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈的代码。
等本轮事件循环执行完了之后又会跳回到async函数中等待await后面表达式的返回值
如果返回值为非 promise 则继续执行 async 函数后面的代码,否则将返回的 promise 放入 promise 队列(Promise的Job Queue)

执行机制
  • 首先我们知道js单线程语言,任务可以分为同步任务,异步任务,当然也可以分为宏任务,微任务。
任务举例
宏任务整体js代码、setTimeout、setInterval等
微任务Promise,process.nextTick等
  • 执行机制(event loop)
    在这里插入图片描述

    • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
    • 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
    • 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
    • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
  • 事件循环、宏任务、微任务关系图
    在这里插入图片描述

实例讲解

下面举个栗子:

	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
	asynic2
	promise1
	script end
	async1 end
	promise2
	setTimeout

具体解释:

  1. 整体代码作为宏任务(同步任务)从上至下执行,首先打印script start
  2. 遇到setTimeout异步任务,那么将其回调函数注册后分发到宏任务Event Queue
  3. 接下来遇到async function,打印async1 start
  4. 执行await后面的async2(),打印出asynic2,产生一个微任务,分发到Event Queue,等待返回一个promise.resolve(undefined)
  5. new Promise立即执行打印promise1,产生一个微任务,分发到Event queue,等待返回一个promise.resolve()
  6. 打印script end,同步任务首次结束,下面执行异步任务
  7. 先看Event queue 队列里面是否有微任务,如果存在首先执行微任务,打印async1 end
  8. 然后继续打印 promise2
  9. 最后打印出event queue 队列里面的宏任务,打印出 setTimeout

尝试解释下面这段代码吧

	async 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();
   	    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");
   		 }
   	 );
   	promise.then((val)=> { console.log(val) });
   	
   	console.log("test end...")

参考文章:

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值