原文连接:davidwalsh.name/async-awaitjavascript
JavaScript Promise 是替代传统回调函数的一个方案,是回调函数的一个改进版。但使用 Promise 会让代码中大量出现 then 方法,一长串的那种。ES2017 引入了一种新的处理异步任务的方式----async 函数,它比使用 Promise API 更加简洁。java
引入的 async 函数,使用了两个新的关键字:async 和 await。web
一例胜千言,先看一个简单的使用 async 和 await 的例子。编程
// 将函数声明为一个 async 函数,这样就能在内部使用 await 了
async function fetchContent() {
// 使用 await,而非 fetch.then
let content = await fetch('/');
let text = await content.text();
// async 函数最终返回一个 resolved 状态的 Promise 对象,
// Promise 对象的 then 回调方法接收的参数就是这里的 text
return text;
}
// 调用 async 函数
let promise = fetchContent.then(...);
复制代码
async 函数以 async 关键字标记,await 只能用在 async 函数中。await 后面紧跟的是生成 Promise 对象的(promise-yielding)操做,对应这里的 fetch API。只有等到第一个 await 后面的操做完成后,才会继续执行后面的代码。最终,async 函数返回一个 resolved 状态的 Promise 对象,而这个 Promise 对象的 then 回调方法中,接收的参数就是 text。json
让咱们看一下,怎么将一个 Promise 例子改写成 async 函数的形式。promise
// 以前:回调城!
fetch('/users.json')
.then(response => response.json())
.then(json => {
console.log(json);
})
.catch(err = {
console.log(err);
});
// 以后:再也不有任何回调!
async function getJson() {
try {
let response = await fetch('/users.json');
let json = await response.json();
console.log(json);
} catch (err) {
console.log(err);
}
}
复制代码
是否是代码变简洁、好看了呢。异步
下面介绍了几种使用 async 函数的场景和方式。async
匿名 async 函数函数
let main = (async function () {
return await fetch('/');
})();
复制代码
async 函数声明fetch
async function main() {
return await fetch('/');
}
复制代码
async 函数表达式
let main = async function () {
return await fetch('/');
};
// 也能够使用箭头函数哦!
let main = async () => {
return fetch('/');
};
复制代码
当作参数的 async 函数
document.body.addEventListener('click', async function () {
return await fetch('/');
});
复制代码
做为对象和类的方法
// 做为对象方法
let obj = {
async method() {
return await fetch('/');
}
};
// 做为类方法
class MyClass {
async method() {
return await fetch('/');
}
}
复制代码
你看到了,async 函数除了自身提供的超炫功能外,TM 跟普通函数使用起来是同样同样的!
传统 rejected 状态的 Promise 对象使用 catch 方法捕获错误。而 await 至关因而已经处理了 resolved 状态下 Promise 对象返回的数据,因此在处理错误时,await 借助了 try/catch:
try {
let x = await myAsyncFunction();
} catch (err) {
// Error!
}
复制代码
虽然,try/catch 处理错误的方式看起来很老套,可是相对于引入 await 给咱们带来的便捷,这根本算不上什么(要否则还要怎样)。
Google 的 Jake Archibald 在 async functions 文档 提出了一个很好的建议----不要同时平行地使用多个 await 语句,这会致使等待时间层层累加,若是可能的话,应该当即发出异步任务,以后再使用 await 等待任务完成(会节省时间的呦)。
// 一共要花掉 1000ms!
async function series() {
await wait(500);
await wait(500);
return "done!";
}
// 仅花掉 500ms!
async function parallel() {
const wait1 = wait(500);
const wait2 = wait(500);
await wait1;
await wait2;
return "done!";
}
复制代码
第二种状况让两个异步请求同时发出,第一个请求在 500ms 后结束后,轮到第二个请求的时候,也已经完成并当即就能返回结果。这种状况适应于无依赖的请求之间。
我最喜欢的 Promise API 的功能之一就是 Promise.all
,它会等待全部的 Promise 对象完成以后再处理数据。咱们也能够在 Promise.all
上使用 await:
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
复制代码
记住,async/await 和 Primose 对象在本质上是同样的,这是咱们可以使用 await Promise.all 等待多个 resolved 状态 Promise 对象返回数据的缘由。
使用 Promise 接口编程仍然很优秀,可是相比于 async 和 await,在维护性上略输一筹。
(完)