async和await

2019/1/12 Javascript

# async 有什么作用

async 函数(包含函数语句、函数表达式、Lambda 表达式)会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过Promise.resolve()封装成 Promise 对象。

async function test() {
  return '1';
}
console.log(test()); // -> Promise {<resolved>: "1"}

如果async函数没有返回值,它会返回 Promise.resolve(undefined)

Promise 的特点——无等待,所以在没有await的情况下执行async函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。

# await 有什么作用

await等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有特殊限定)。

因为async函数返回一个 Promise 对象,所以await 可以用于等待一个async函数的返回值——这也可以说是await在等async函数,但要清楚,它等的实际是一个返回值。注意到await不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。

var b = async () => {
  var a = 0;
  a = a + (await 10);
  console.log('1', a); // -> '1' 10
  a = (await 10) + a;
  console.log('2', a); // -> '2' 20
};
b();

await 表达式的运算结果取决于它等的东西。 如果await后的表达式不是一个 Promise 对象,那await 表达式的运算结果就是它的结果。

如果await后的表达式是一个 Promise 对象,await 会阻塞后面的代码,等着 Promise 对象resolve,然后得到resolve的值,作为await表达式的运算结果。

await 只能用在 async 里面

# async/await 做了什么事?

async会将其后的函数的返回值封装成一个 Promise 对象,而 await会等待这个 Promise 完成,并将其resolve 的结果返回出来。

function sleep() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('finish');
      resolve('sleep');
    }, 2000);
  });
}
async function test() {
  let value = await sleep();
  console.log('object');
}
test();

在这个函数里,await会等待 sleep() 返回一个值,先打印finish,然后再打印object

# 一段代码

var a = 0;
var b = async () => {
  a = a + (await 10);
  console.log('2', a); // -> '2' 10
  a = (await 10) + a;
  console.log('3', a); // -> '3' 20
};
b();
a++;
console.log('1', a); // -> '1' 1

首先函数 b 先执行,在执行到 await 10 之前变量 a 还是 0,因为在 await 内部实现了 generators ,generators 会保留堆栈中东西,所以这时候 a = 0 被保存了下来

因为 await 是异步操作,遇到 await 就会立即返回一个 pending 状态的 Promise 对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行,所以会先执行 console.log('1', a)

这时候同步代码执行完毕,开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 10

然后后面就是常规执行代码了