async/await通过”同步“实现异步
学习Event Loop时,有async/await,倒是学习过,也就看过就忘了,在这深入的学习下,做个总结。
虽然是ES7里面的,但是很早就出来被使用,面试的时候也被问到过。接触异步最多的还是接口、setTimeout、Promise,相对于async,可能对promise更熟悉些,其实async也算得上Generator 函数的语法糖。promise调用then方法链式回调,async代码更优雅,符合阅读习惯,使用await使用”同步“的方式实现了异步。
1)async声明函数里有异步操作,await表示等待(只能在async函数内部使用),相当于promise里的then当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
如果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之后输出32)返回值是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
- 使用Promise和async-await实现的一个异步遍历+同步执行任务的实例
- 一种通过async/await实现函数同步执行的方式
- ES7之async/await 同步还是异步
- .NET4.0中使用4.5中的 async/await 功能实现异步
- 实际案例:在现有代码中通过async/await实现并行
- HttpClient实现同步(sync)和异步(Async)
- ASP.NET WebForm中用async/await实现异步出人意料的简单
- 实际案例:在现有代码中通过async/await实现并行
- 通过 NSURLConnection实现 同步/ 异步 请求 (WXHL)
- NodeJs通过async/await处理异步的方法
- PHP协程(2):通过生成器栈实现异步的同步写法
- NodeJS-Promise、await、async异步变同步
- 利用async和await异步操作解决node.js里面fs模块异步读写,同步结果的问题
- Promise,同步异步,Async/await
- ASP.NET WebForm中用async/await实现异步
- [C#] .NET4.0中使用4.5中的 async/await 功能实现异步
- asp.net webform中使用async,await实现异步操作
- c++实现半同步半异步I/O的设计模式(half sync/half async)
- 使用 async 和 await,实现 fetch 同步请求
- ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用!因此,ES transport client可以同步调用也可以异步(不过底层的socket必然是异步实现)