js async、await函数

  1. js async/await函数

js async/await函数

async函数就是generator函数的语法糖,一般结合Promise使用

我们可以把generator函数函数改写成async/await函数,例如

var fs = require('fs');
var co = require('co');

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

function* read() {
    // resolve multiple promises in parallel
    var a = yield readFile('./data/a.text')
    var b = yield readFile('./data/b.text')

    console.log(a.toString());
    console.log(b.toString());
}

co(read)

改写成

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.toString());
        });
    });
};

async function read() {
    // resolve multiple promises in parallel
    var a = await readFile('./data/a.text')
    var b = await readFile('./data/b.text')

    console.log(a.toString());
    console.log(b.toString());
}

read()

输出和上面的generator函数是一样的,但是我们对比可以发现,async函数只是将generator函数的*去掉了,然后在前面加了一个async,函数内部的yield替换成了await,其他的都没有变化

async函数的改进,体现在以下几点:

  • 内置执行器:我们发现是用async函数,我们不需要引入co模块,就能使用,因为async函数内置了执行器
  • 更好的语义:async/await相比generatoryield有更好的语义,async表示函数内部有异步操作,而await表示紧跟在后面的表达式需要等待结果,才能继续执行下面的代码
  • 更广的适用性:co模块约定,yield命令后面只能是thunk函数或 Promise对象,而async函数的await命令后面,可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即resolvedPromise对象)。
  • 返回值是Promiseasync函数的返回值是Promise对象,这比 generator函数的返回值是iterator对象方便多了。你可以用then方法指定下一步的操作。

async函数的返回值是一个Promise对象,函数内部return语句返回的值,会成为then方法回调函数的参数。

async function fn() {
    return 123
}

fn().then(d => console.log(d))  // 123

错误处理
async函数的错误处理方式可以放在函数内部也可以放在函数外部

放在函数内部

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出错了');
    });
  } catch(e) {
  }
  return await('hello world');
}

放在函数外部

async function f() {
  await new Promise(function (resolve, reject) {
    throw new Error('出错了');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))

如果有多个await命令,可以统一放在try…catch结构中。

async function f() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);
    console.log('Final: ', val3);
  }
  catch (err) {
    console.error(err);
  }
}

思考一下下面的代码为什么会按照1、3、2的顺序输出,那是因为执行fn函数,执行console.log(1),然后返回一个Promise对象,又由于Promise对象的then属于微任务,放到微任务执行队列里面,执行下面的console.log(3),后面执行栈没有代码了,然后执行微任务队列里的任务,执行console.log(2)

async function fn() {
    console.log(1)
    return 2
}

fn().then(d => console.log(d))
console.log(3)

输出结果

1
3
2

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com