您的位置:首页 > 大数据 > 人工智能

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

2019-08-14 16:04 1621 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_35423431/article/details/99544055

学习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)
}

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

async function fun2(p) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return 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()
// let t1 = await fun1().catch((err) => console.log(err))
console.log(t1)
}

async function fun1() {
return new Promise((resolve, reject) => {
setTimeout(function(){
return 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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: