javaScript 异步函数

296 阅读2分钟

简单介绍

异步函数是ES8新增的,用来解决利用异步结构组织代码的问题,是javaScript最重要的工具之一。

它有两个关键字:async、await。

async关键字用来声明函数为异步函数,使函数有异步特性。

异步函数的特性

​ 1、如果有返回值n,会返回一个被Promise.resolve(n)包装的Promise对象。

async function foo(){
  return 1
}
foo().then(console.log)//1

//效果等同于
async function foo() {
  return Promise.resolve(1)
}
foo().then(console.log)//1

2、能捕获抛出的错误,但不能捕获拒绝状态的Promise,这跟Promise捕获机制相反了

async function foo1(){
  throw 1
}
foo1().catch(console.log)//1

async function foo2() {
  Promise.reject(3)
}
foo2().catch(console.log) //不能捕获,无打印

/* 最终打印错误未被捕获的报错信息*/

3、async不能声明箭头函数

async/await

await关键字可以暂停异步函数代码的执行,等待Promise解决,再往后执行。

//async函数不使用await关键字,和普通函数基本没区别
async function foo() {
  let p = new Promise((resolve) => setTimeout(resolve,1000,1))
  console.log(p);
  console.log(2);
}
//使用await关键字,就有了等待的效果
foo()//先打印Promise { <pending> } ,再打印2
async function foo() {
  let p = new Promise((resolve) => setTimeout(resolve,1000,1))
  console.log(await p);
  console.log(2);
}

foo()//先打印1 ,再打印2

await关键字只能出现在异步函数的顶层主体,否则会抛出SyntaxError错误:SyntaxError: await is only valid in async functions and the top level bodies of modules

async function foo() {
  let p = new Promise((resolve) => setTimeout(resolve,1000,1))
  console.log(await '1');//1
  setTimeout(() => { await '1' }, 500)//报错:await is only valid in async functions and the top level bodies of modules
}

注意:await并非只是等待一个值,那么简单。javaScript 运行的时候,遇到await 关键字会记录它暂停的位置,也就是添加到了任务队列中,等到右边的值可用了,javaScript会向消息队列中推送一个恢复异步函数执行的任务。即使await的是一个直接可用的值也是一样的。

异步函数策略

异步函数策略只是一些应用场景

1、实现异步延迟

async function sleep(delay) {
  return new Promise((resolve) => setTimeout(resolve, delay))
}

async function foo() {
  const startTime = Date.now()
  await sleep(1500);//延迟约500ms 
  console.log(`耗时:${Date.now() - startTime}ms`);
}

foo()

2、平行执行

async function randomDelay(id) {
  const delay = Math.random() * 1000;
  return new Promise((resolve) => setTimeout(() => {
    // console.log(`${id} finished`);
    setTimeout(console.log, 0, `${id} finished`)
    resolve();
  }), delay)
}

async function foo() {
  const start = Date.now()
  const p0 =  randomDelay(0);
  const p1 =  randomDelay(1);
  const p2 =  randomDelay(2);
  const p3 =  randomDelay(3);
  const p4 =  randomDelay(4);
  await p0;
  await p1;
  await p2;
  await p3;
  await p4;
  // console.log(`耗时:${Date.now() - start} ms`);
  setTimeout(console.log, 0, `耗时:${Date.now() - start} ms` )
}
foo()
/* 输出打印:
    0 finished
    1 finished
    2 finished
    3 finished
    4 finished
    耗时:14 ms
*/

3、串行执行

async function add1(x) { return x + 1}
async function add2(x) { return x + 2 }
async function add3(x) { return x + 3 }
async function adds(value) {
  let result = value
  for (const fn of [add1, add2, add3]) {
    result = await fn(result);
  }
  return result
}
adds(9).then(console.log) //15