async 函数
async 函数
  含义
    ES2017 标准引入了 async 函数，，使得异步操作变得更加方便
    async 函数本质上就是 Generator 函数的语法糖
    一比较就会发现，async函数就是将 Generator 函数的星号（*）替换成async，将yield替换成await，仅此而已
    async函数对 Generator 函数的改进，体现在以下四点
      （1）内置执行器
      （2）更好的语义
      （3）更广的适用性
      （4）返回值是 Promise
      改进
  基本用法
    async函数返回一个 Promise 对象，可以使用then方法添加回调函数
    当函数执行的时候，一旦遇到await就会先返回，等到异步操作完成，再接着执行函数体内后面的语句。
  语法
    返回 Promise 对象
      async函数内部return语句返回的值，会成为then方法回调函数的参数
      async函数内部抛出错误，会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
      async函数返回一个 Promise 对象
    Promise 对象的状态变化
      async函数返回的 Promise 对象，必须等到内部所有await命令后面的 Promise 对象执行完，才会发生状态改变，除非遇到return语句或者抛出错误
    await 命令
      正常情况下，await命令后面是一个 Promise 对象，返回该对象的结果。如果不是 Promise 对象，就直接返回对应的值。
    错误处理
      如果await后面的异步操作出错，那么等同于async函数返回的 Promise 对象被reject
    使用注意点
      await命令后面的Promise对象，运行结果可能是rejected，所以最好把await命令放在try...catch代码块中
      多个await命令后面的异步操作，如果不存在继发关系，最好让它们同时触发。
      await命令只能用在async函数之中，如果用在普通函数，就会报错
      async 函数可以保留运行堆栈
  async 函数的实现原理
    async 函数的实现原理，就是将 Generator 函数和自动执行器，包装在一个函数里
  与其他异步处理方法的比较
    async 函数与 Promise、Generator 函数的比较。Async 函数的实现最简洁，最符合语义，几乎没有语义不相关的代码。它将 Generator 写法中的自动执行器，改在语言层面提供，不暴露给用户，因此代码量最少。如果使用 Generator 写法，自动执行器需要用户自己提供
  提案：顶层 await
    目前await命令只能出现在 async 函数内部，否则都会报错
    现在有一个语法提案，允许在模块的顶层独立使用await命令
  async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err);
});
}
  // 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
  async function f() {
return 'hello world';
}
f().then(v => console.log(v))
// "hello world"
  const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};