Skip to the content.

Async 函数

异步编程的最高境界,就是根本不用关系它是不是异步

async 函数如同隧道尽头的光亮,可能是异步操作的终极方案

async 函数是什么

aysnc 函数就是 Generator 函数的语法糖

Generator 函数读取两个文件

var fs = require("fs");

var readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function (error, data) {
      if (error) reject(error);
      resolve(data);
    });
  });
};

var gen = function* () {
  var f1 = yield readFile("/etc/fstab");
  var f2 = yield readFile("/etc/shells");
  console.log(f1.toString());
  console.log(f2.toString());
};

async 写法

var asyncReadFile = async function () {
  var f1 = await readFile("/etc/fstab");
  var f2 = await readFile("/etc/shells");
  console.log(f1.toString());
  console.log(f2.toString());
};

async 函数将 Generator 函数的 * 替换成了 async
将 yield 替换成了 await



async 函数优点

async 函数对 Generator 函数的改进体现在以下三点

内置执行器

Generator 函数的执行必须依靠执行器,才有了co 函数库
而 async 函数自带执行器

更好的语义

async await 比起星号和 yield 语义更清楚
async 表示函数里有异步操作 await 表示紧跟在后面的表达式需要等待返回结果

更广泛的适用性

co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。



async 函数的用法

async 函数和 Gernerator 函数一样,返回一个 Promise 对象,可以使用 then 方法添加回调函数
当函数执行的时候,遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体后面的语句

async function getStockPriceByName(name) {
  var symbol = await getStockSymbol(name);
  var stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName("goog").then(function (result) {
  console.log(result);
});



async 函数的实现

async 的实现时将 Generator 函数和自动执行器包装在一个函数里

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}

所有的 async 函数都可以写成上面的第二种形式,其中的 spawn 函数就是自动执行器。

下面给出 spawn 函数的实现,基本就是前文自动执行器的翻版。

function spawn(genF) {
  return new Promise(function (resolve, reject) {
    var gen = genF();
    function step(nextF) {
      try {
        var next = nextF();
      } catch (e) {
        return reject(e);
      }
      if (next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(
        function (v) {
          step(function () {
            return gen.next(v);
          });
        },
        function (e) {
          step(function () {
            return gen.throw(e);
          });
        }
      );
    }
    step(function () {
      return gen.next(undefined);
    });
  });
}

参见