async和await的讲解

koala 2019-5-10 ES6awaitasync

# 声明 async 函数的几个方法

//普通的函数声明

async function A() {}
1

//声明一个函数表达式

let A = async function() {}
1

//async 形式的箭头函数

let A = async () => {}
1

# 初识 async 和 await

async 与 await 实例应用,基础代码 控制器调用与 server 中查询数据

exports.getBlogList = async (ctx, next) => {
  return (ctx.body = await ArticleServer.getBlogListServer())
}

exports.getBlogListServer = async () => {
  let where = {
    id: '1',
  }
  let blogList = await articleBlogDa.findAll({ where: where })
  console.log('哈哈哈' + blogList)
  return blogList
}
1
2
3
4
5
6
7
8
9
10
11
12
  1. 方法执行后的返回值:await 命令后面可以是 Promise 对象或值,如果是值,就会转到一个立即 resolve 的 Promise 对象。async 函数返回的是一个 Promise 对象,如果结果是值,会经过 Promise 包装返回。

  2. await 与并行:如果在一个 async 的方法中,有多个 await 操作的时候,程序会变成完全的串行操作,一个完事等另一个但是为了发挥 node 的异步优势,当异步操作之间不存在结果的依赖关系时,可以使用 promise.all 来实现并行,all 中的所有方法是一同执行的。

  3. 执行后的结果:async 函数中,如果有多个 await 关键字时,如果有一个 await 的状态变成了 rejected,那么后面的操作都不会继续执行,promise 也是同理 await 的返回结果就是后面 promise 执行的结果,可能是 resolves 或者 rejected 的值使用场景循环遍历方便了代码需要同步的操作(文件读取,数据库操作等)

async 与 await 一些注意关键点小结

  • await关键字必须位于async函数内部
    
  • await关键字后面需要一个promise对象(不是的话就调用resolve转换它)
    
  • await关键字的返回结果就是其后面Promise执行的结果,可能是resolved或者rejected的值
    
  • 不能在普通箭头函数中使用await关键字,需要在箭头函数前面添加async
    
  • await用来串行的执行异步操作,现实现并行可以考虑promise.all
    

# async 与 await 缺点

async 函数中,如果有多个 await 关键字时,如果有一个 await 的状态变成了 rejected,那么后面的操作都不会继续执行,promise 也是同理有这样一个函数 async

function getData()
{
let value=await get();
value++;
await set();//set完成后返回数据
return value;

}
1
2
3
4
5
6
7
8

直接调用

var value = getData()
1

是对于这个函数直接调用的时候并不是你想要的返回值,因为 async 方法返回的永远是一个 promise,即使开发者返回的是一个常量,也会被自动调用的 promise.resolve 方法转换为一个 promise。因此对于这种情况,上层调用方法也需要是 async 函数,采用如下方法

async function xxxx() {
  var value = await getData()
  return value
}
1
2
3
4

对于这种调用,如果还存在更高层次的方法调用,那么从底层的异步操作开始,一直到最顶层一个不需要返回值的函数为止,全部的方法都要变成 async。

# await 与 async 大多数人的误区

这个误区在一道面试题那篇文章中详细讲解过,但是还是想提一下。 看一段代码:

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2')
}
async1()
console.log('i am koala')
1
2
3
4
5
6
7
8
9
10

我想会有一些开发者认为 await 是把同步变为异步,执行顺序是这样

async1 start
async2
async1 end
i am koala
1
2
3
4

然而并不是,正确的执行顺序是

async1 start
async2
i am koala
async1 end
1
2
3
4

解释一下原因:

“ async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。” ——阮一峰 ES6

简单的说,先去执行后面的同步任务代码,执行完成后,也就是表达式中的 Promise 解析完成后继续执行 async 函数并返回解决结果。(其实还是本轮循环 promise 的问题,最后的 resolve 属于异步,位于本轮循环的末尾。)

# 给我留言

关注作者公众

和万千小伙伴一起学习

加入技术交流群

扫描二维码 备注 加群