ECMAScript 6 学习(二)async函数

1、什么是async函数

2、用法

  2.1基本用法

3、语法

  3.1返回promise对象

  3.2promise状态的变化

  3.3await命令

 

 

1、什么是async函数

async函数也是异步编程的解决方案。

async函数是对是对generator函数进行了改进。

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

后边的gen函数,写成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函数对generator函数进行改进,体现以下四点。

(1)内置执行器。

generator函数的执行必须依靠执行器,而async函数自带执行器,也就是说,async函数的执行与普通函数一模一样,只要一行。

下面代码调用了asyncReadFile函数,然后就会自动执行,输出最后的结果。这个完全不像generator函数,需要调用next方法,才能得到最终的结果。

var result=asyncReadFile();

(2)更好的语义

async和await,比起星号(*)和yield,语义更清楚。async表示函数中有异步操作,await表示紧跟其后的表达式需要等待结果。

(3)更广的适用性

yield命令后面只能是Thunk函数或者promise对象,而async函数的await命令后面,可以是promise对象和原始类型的值(数值,字符串和布尔值,但这等同于同步操作)

(4)返回值是promise

async函数的返回值是promise对象,执行generator函数返回一个遍历器对象(Iterator对象)方便多了,也就是说,async函数可以看做是多个异步操作,包装成一个promise对象,而await命令是内部then命令的语法糖。

 

2、用法

2.1基本用法

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

举一个栗子

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 5000);

上面代码指定5秒后输出hello world。

 async函数多种使用形式

//函数声明
async function foo() {}

//函数表达式
const foo = async function () {}

//对象的方法
let obj = { async foo() {} }
obj.foo().then(...)

//箭头函数
const foo = async () => {};

//class方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

 

3、语法

 async函数的语法规则总体上比较简单,难点是错误处理机制。

3.1返回的promise对象

async函数返回的是promise对象。

async函数内部return语句返回值,会成为then方法回调函数的参数

async function f() {
  return 'hello world';
}

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

上面代码中,函数f内部return 命令返回值,会被then方法回调函数接收到。输出“hello world”。

async函数内部抛出的错误,会导致返回的promise对象变成reject状态。抛出的错误对象会被catch方法回调函数接收到。

 

3.2promise对象状态变化 

async函数返回的promise对象,必须等到内部的所有的await命令后边的promise对象执行完,才会发生状态的改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

举个栗子

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)

上面代码中,函数getTitle内部有三个操作:抓取网页,取出文本,匹配页面标题。只有三个操作全部完成,才会执行then方法里面console.log。

 

 3.3 await命令 

 正常情况下,await命令后边是一个promise对象。如果不是,会被转成一个一个立即resolve的promise对象。

async function f() {
  return await 123;
}

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

上面代码中,await命令的参数是数值123,他被转成promise对象,并立即resolve。

await命令后边的promise对象如果变成reject状态,则reject的参数会被catch方法的回调函数接收到。

举个栗子

async function f() {
  await Promise.reject('出错了');
}

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

上面代码中,await语句前面没有return,但是reject方法的参数依然传入catch方法的回调函数,这里如果在wawait前面加上return,效果是一样的。

 只要一个await语句后面的promise变成了reject,那么整个async函数都会中断执行。

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

上面代码中,第二个await语句是不会执行的,因为第一个await语句状态变成了reject

 

posted @ 2017-07-30 11:29  saucxs  阅读(960)  评论(0编辑  收藏  举报