async/await通过”同步“实现异步

学习Event Loop时,有async/await,倒是学习过,也就看过就忘了,在这深入的学习下,做个总结。

虽然是ES7里面的,但是很早就出来被使用,面试的时候也被问到过。接触异步最多的还是接口、setTimeout、Promise,相对于async,可能对promise更熟悉些,其实async也算得上Generator 函数的语法糖。promise调用then方法链式回调,async代码更优雅,符合阅读习惯,使用await使用”同步“的方式实现了异步。

当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

1)async声明函数里有异步操作,await表示等待(只能在async函数内部使用),相当于promise里的then

如果B接口的参数需要A接口请求结果,需要等待A接口请求完成,才能请求B接口,如下实例:

async function ay(){
// fun1完成以后fun2才会发生 继发关系                               
	let t1 = await fun1()
	let t2 = await fun2(t1)
	console.log(t2)
}

function fun1() {
	return new Promise((resolve, reject) => {
		setTimeout(function(){
			resolve(1)
		},1000)
	})
}

function fun2(p) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(2 + p)
		},2000)
	})
}
ay()// 3s之后输出3
2)返回值是promise对象,使用then获取asycn返回的结果。
async function fun3(x) {
	return x
}
let result = fun3(3)
console.log(result)

在这里插入图片描述

async function fun3(x) {
	return x
}
fun3(3).then((r) => console.log(r))
3)两个异步同时进行

当需要两个接口同时请求成功之后才进行下一步操作,如何处理。

按如下顺序执行,是需要等待fun1加载完成后,fun2才能开始加载,时长就会变长。

let t1 = await fun1()
let t2 = await fun2()

fun1和fun2是同时触发,缩短程序执行时间

async function ay(){
	let [ t1, t2 ] = await Promise.all([ fun1(), fun2() ])
	console.log(t1)
	console.log(t2)
}

async function fun1() {
	return new Promise((resolve, reject) => {
		setTimeout(function(){
			return resolve(1)
		},2000)
	})
}

async function fun2(p) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			return resolve(2)
		},2000)
	})
}
ay()
4)捕获异常

在实际场景中,存在接口获取数据异常,如果返回reject,执行到await会报错,并且不会执行后续的代码,由于async返回的是promise对象,可以使用catch去捕获,也可以使用try/catch

async function ay(){
	let t1 = await fun1()
			.then(result => console.log(result))
			.catch((err) => console.log(err))
}

function fun1() {
	return new Promise((resolve, reject) => {
		setTimeout(function(){
			reject('1')
		},2000)
	})
}

在这里插入图片描述

5)实现原理

将 Generator 函数和自动执行器,包装在一个函数里。

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}
6)Event Loop

在浏览器中,异步机制是借助 event loop 来实现的,event loop 是异步的一种实现机制。
可以看下异步任务执行顺序

console.log('script start') // 1️⃣

async function async1() { // 1️⃣
  await async2() // 1️⃣
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end') 
}
async1()

setTimeout(function() {
  console.log('setTimeout')
}, 0)

new Promise(resolve => { // 1️⃣
  console.log('Promise') // 1️⃣
  resolve()
})
  .then(function() {
    console.log('promise1')
  })
  .then(function() {
    console.log('promise2')
  })

console.log('script end') // 1️⃣

在这里插入图片描述
上图标记的1️⃣都是属于同步任务的,可能await async2()会有些疑问,转换成promise:

function async1() { 
  return new Promise((resolve, reject)=>{
	async2()
	resolve()
  }).then(() => {
	console.log('async1 end')
  })
}
function async2() {
  console.log('async2 end') 
}
async1()

看到一个promise的实例

new Promise(resolve => {
    resolve(1);
    Promise.resolve().then(() => console.log(2));
    console.log(4)
}).then(t => console.log(t)); // a
console.log(3);

是阮老师推特上的一道题,首先 Promise 构造函数中的对象同步执行,碰到 resolve(1),将当前 Promise 标记为 resolve,但是注意它 then 的回调函数还没有被注册,因为还没有执行到 a 处。继续执行又碰到一个 Promise,然后也立刻被 resolved 了,并且执行它的 then 注册,将第二个 then 的回调函数推入空的 microtaskQueue 中。继续执行输出一个 4,然后 a 处的 then 现在才开始注册,将第一个 Promise 的 then 回调函数推入 microtaskQueue 中。继续执行输出一个 3。现在 task queue 中的任务已经执行完毕,到了 microtask checkpoint flag,发现有两个 microtask,按照添加的顺序执行,第一个输出一个 2,第二个输出一个 1,最后再更新一下 UI 然后这一轮 event loop 就结束了,最终的输出是"4 3 2 1"
摘自:fi3ework

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值