# Async 和 Await

async 是 ES7 提出的新特性,是 Generator 的语法糖。既然是语法糖,那我们首先说一下它的改进之处。

# Async 对 Generator 的改进之处

# 写法改进

// Generator
function* foo() {
  yield 'b'
}

// Async Await
async function foo() {
  await 'b'
}

对比发现,async 函数在写法上将 Generator 的星号替换成 async 关键字,yield 关键字替换为 await,更符合异步编程语义化。

# 内置执行器

Generator 函数必须依靠执行器,而 async 函数自带执行器。所以 async 函数不用像 Generator 函数一样要用 next 方法才会执行,完全可以和普通函数一样。

# 更好的实用性

co 模块约定,yield 命令后面只能是 Thunk 函数或者是 Promise 对象,而 async 函数的 await 后面可以是任意类型的值,并且会将后面的值转换成为一个立即执行 resolved 的 Promise 对象。

# 返回值为 Promise

async 函数的返回值是一个 Promise 对象,可以用 then 方法;Generator 函数返回的是一个 Iterator 对象。

# Async 基本用法

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到一步操作完成,再接着执行函数体内后面的语句,并且 await 必须在 async 函数内,不然会报错。

async 函数中的返回值会成为返回的 Promise 对象中 resolve 的值;当 async 函数中抛出一个错误的时候,会成为返回 Promise 对象中 reject 的值。

# Await 表达式

await 语句后面跟随的是一个 thenable 对象(即包含 then 的对象,类 Promise 对象),此时 await 会把他们当成是一个标准的 Promise 来处理,并且返回该 Promise resolved 的值。如果是基本数据类型的话,则会直接返回这个值。

当 await 后面的 Promise 抛出一个错误时,此时会直接跳出 async 函数并被 async 函数的 catch 捕获。如果想要不中断 async 函数继续执行的话,可以尝试在内部对 await 用 try catch 包裹起来。

# await 后加 普通函数, 普通函数立即执行, 跟没加await一样

async function test(params) {
	await setTimeout(() => {
		console.log(1);
	}, 1000);
	console.log(2);
}

test();
// 2 
// 1
function normalFunc() {
	console.log('normalFunc');
}

async function test1() {
	await normalFunc();
	console.log(2);
}

test1();
// normalFunc
// 2

# await 串行

getBar() 会等待 getFoo()返回后执行。

async function parell(){
    let foo = await getFoo();
    let bar = await getBar();
}

# await 并行

getBar(),getFoo() 同时执行。

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

# async在循环中使用

在forEach中的并行执行的

function dbFuc(db) { //这里不需要 async
  let docs = [{}, {}, {}];

  // 可能得到错误结果
  docs.forEach(async function (doc) {
    await db.post(doc);
  });
}

在 for...of 和普通for中是串行执行的

async function dbFuc(db) {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await db.post(doc);
  }
}