async函数

async函数

含义

async是Generator的语法糖

async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
//等价于
const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
基本用法

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', 50);//指定 50 毫秒以后,输出hello world

async函数有多种适用形式

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

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

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

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

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

const storage = new Storage();
storage.getAvatar('jake').then();

// 箭头函数
const foo = async () => {};
语法
返回Promise对象

async函数返回一个Promise对象

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

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

Promise 对象的状态变化

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)
// "ECMAScript 2017 Language Specification"
//上面代码中,函数getTitle内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行then方法里面的console.log
await命令

正常情况下,await命令后面是一个Promise对象,返回该对象的结果

如果不是Promise对象,就直接返回对应的值

async function f() {
  // 等同于
  // return 123;
  return await 123;
}

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

如果await命令后面是一个thenable对象(即定义了then方法的对象),那么await会将其等同于Promise对象

class Sleep {
  constructor(timeout) {
    this.timeout = timeout;
  }
  then(resolve, reject) {
    const startTime = Date.now();
    setTimeout(
      () => resolve(Date.now() - startTime),
      this.timeout
    );
  }
}

(async () => {
  const sleepTime = await new Sleep(1000);
  console.log(sleepTime);
})();
// 1000

JavaScript一直没有休眠的语法,借助await命令可以让程序停顿指定的时间

function sleep(interval) {
  return new Promise(resolve => {
    setTimeout(resolve, interval);
  })
}

// 用法
async function one2FiveInAsync() {
  for(let i = 1; i <= 5; i++) {
    console.log(i);
    await sleep(1000);
  }
}

one2FiveInAsync();

await后面的Promise对象如果状态变为reject状态,则reject的参数会被catch方法的回调函数接收到

async function f() {
  await Promise.reject('出错了');
}	//await前面没有return,但是reject方法的参数还是传入了catch方法的回调函数
//如果在await前面加上return,效果是一样的
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了

任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行

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

如果希望前一个异步操作失败,后一个不会中断,就可以将await放在try…catch结构里面,不管这个异步操作是否成功,第二个await都会执行

async function f() {  try {    await Promise.reject('出错了');  } catch(e) {  }  return await Promise.resolve('hello world');}f().then(v => console.log(v))// hello world

另一种方法是在await后面的Promise对象再跟一个catch方法

async function f() {  await Promise.reject('出错了')    .catch(e => console.log(e));  return await Promise.resolve('hello world');}f().then(v => console.log(v))// 出错了// hello world
错误处理

防止错误的方法,就是将其放在try…catch代码块之中

多个await也可以统一放在try…catch结构中

使用注意点
  • await后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中
  • 多个await命令后面的异步操作,如果不存在继发关系,最好让他们同时触发
  • await命令只能用在async函数之中,如果用在普通函数,就会报错
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值