async...await用法

216 阅读3分钟

async关键字

  1. 普通函数调用,返回"Hello"
function hello() { return "Hello" };
hello(); //"Hello"
  1. 声明async调用,返回一个promise
async function hello() { return "Hello" };
hello(); //Promise {<resolved>: "Hello"}

以下是等价的写法:

//创建一个异步函数表达式
let hello = async function() { return "Hello" };
hello(); 

//使用箭头函数
let hello = async () => { return "Hello" };
hello();
  1. 因为返回了一个promise,我们可以使用.then()块
hello().then((value) => console.log(value)); //Hello

//简写
hello().then(console.log); //Hello

await关键字

可以在调用任何返回Promise的函数时使用await,包括Web API函数。

await关键字使JavaScript运行时暂停此行上的代码,允许其他代码在此期间执行,直到异步函数调用返回其结果。一旦完成,您的代码将继续从下一行开始执行。

async function hello() {
  return greeting = await Promise.resolve("Hello");
};

hello().then(alert); //Hello
  1. Can’t use await in regular functions
function f() {
  let promise = Promise.resolve(1);
  let result = await promise; //Uncaught SyntaxError: await is only valid in async function
}
  1. await won’t work in the top-level code
<!DOCTYPE html>
<html lang="en">
  <body>
  </body>
  <script>
  'use strict';
  // syntax error in top-level code
  let response = await fetch('https://cnodejs.org/api/v1/topics');
  let user = await response.json();
  console.log(user);
  </script>
</html>

we can wrap it into an anonymous async function

<script>
  'use strict';
  // syntax error in top-level code
  (async () => {
    let response = await fetch('https://cnodejs.org/api/v1/topics');
    let user = await response.json();
    alert(user);
  })();
</script>
  1. await accepts “thenables”
class Thenable {
  constructor(num) {
    this.num = num;
  }
  then(resolve, reject) {
    // resolve with this.num*2 after 1000ms
    setTimeout(() => resolve(this.num * 2), 1000); // (*)
  }
};

async function f() {
  // waits for 1 second, then result becomes 2
  let result = await new Thenable(1);
  console.log(result);
}

f();
  1. 类方法

我们可以在类/对象方法前面添加async,以使它们返回promises,并await它们内部的promises。

class Person {
  constructor(name) {
    this.name = name;
  }

  async greeting() {
    return await Promise.resolve(`Hi! I'm ${this.name}.`);
  };
}

let jim = new Person('Jim');
jim.greeting().then(console.log); //Hi! I'm Jim.

使用async/await重写promise代码

  1. promise实现
fetch('https://cnodejs.org/api/v1/topics')
.then(response => response.json())
.then(data => {
  console.log(data);
})
.catch(e => {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});
  1. 使用async/await实现
async function myFetch() {
  let response = await fetch('https://cnodejs.org/api/v1/topics');
  let data = await response.json();
  console.log(data);
}

myFetch()
.catch(e => {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});
  1. 重构代码
async function myFetch() {
  let response = await fetch('https://cnodejs.org/api/v1/topics');
  return await response.json();
}

myFetch().then((data) => {
  console.log(data);
})

添加错误处理

async function myFetch() {
  try {
    let response = await fetch('https://cnodejs.org/api/v1/topics');
    let data = await response.json();
    console.log(data);
  } catch(e) {
    console.log(e);
  }
}

myFetch();
async function myFetch() {
  let response = await fetch('https://cnodejs.org/api/v1/topics');
  return await response.json();
}

myFetch().then((data) => {
  console.log(data);
})
.catch((e) =>
  console.log(e)
);

等待Promise.all()

async/await建立在promises之上,因此它与promises提供的所有功能兼容。

async function myFetch(url) {
  const response = await fetch(url);
  return await response.json();
}

async function init() {
  let topicList = myFetch('https://cnodejs.org/api/v1/topics');
  let topicItem = myFetch('https://cnodejs.org/api/v1/topic/5e4fa8531225c9423dcda9d8');
  let userInfo = myFetch('https://cnodejs.org/api/v1/user/lellansin');

  let values = await Promise.all([topicList, topicItem, userInfo]);
  console.log(values);
}

async/await的缺陷

async/await让你的代码看起来是同步的,在某种程度上,也使得它的行为更加地同步。 await关键字会阻塞其后的代码,直到promise完成.

代码可能会因为大量await的promises相继发生而变慢。每个await都会等待前一个完成,而你实际想要的是所有的这些promises同时开始处理(就像我们没有使用async/await时那样)。

有一种模式可以缓解这个问题 ––通过将Promise对象存储在变量中来同时开始它们,然后等待它们全部执行完毕。

function timeoutPromise(interval) {
  return new Promise((resolve, reject) => {
    setTimeout(function(){
      resolve("done");
    }, interval);
  });
};

async function timeTestSlow() {
  await timeoutPromise(3000);
  await timeoutPromise(3000);
  await timeoutPromise(3000);
}

let startTime = Date.now();
timeTestSlow().then(() => {
  let finishTime = Date.now();
  let timeTaken = finishTime - startTime;
  console.log("Time taken in milliseconds: " + timeTaken); //Time taken in milliseconds: 9013
})

另一种写法

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

async function timeTestSlow() {
  await timeout(3000);
  await timeout(3000);
  await timeout(3000);
}

function doit(){
  console.time("doit");
  timeTestSlow().then(() => {
    console.timeEnd("doit");
  })
}
doit(); //doit: 9008.90380859375ms

保存在变量中

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

async function timeTestFast() {
  const timeout1 = timeout(3000);
  const timeout2 = timeout(3000);
  const timeout3 = timeout(3000);

  await timeout1;
  await timeout2;
  await timeout3;
}

function doit(){
  console.time("doit");
  timeTestFast().then(() => {
    console.timeEnd("doit");
  })
}
doit(); //doit: 3002.612060546875ms

More

Making asynchronous programming easier with async and await
developer.mozilla.org/en-US/docs/…

async和await:让异步编程更简单 developer.mozilla.org/zh-CN/docs/…

理解 JavaScript 的 async/await
segmentfault.com/a/119000000…

async 函数的含义和用法
www.ruanyifeng.com/blog/2015/0…

Async/Await:比Promise更好的6个理由
caibaojian.com/asyncawait.…