原来异步函数用起来这么“香”?不信来试试
人生代码
共 3496字,需浏览 7分钟
·
2021-02-22 00:25
今天,我们就来看看几个例子吧。
Rewrite using async/await
改写本章的示例代码,使用async/await代替.then/catch:
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new Error(response.status);
}
});
}
loadJson('no-such-user.json')
.catch(alert); // Error: 404
改写如下:
async function loadJson(url) { // (1)
let response = await fetch(url); // (2)
if (response.status == 200) {
let json = await response.json(); // (3)
return json;
}
throw new Error(response.status);
}
loadJson('no-such-user.json')
.catch(alert); // Error: 404 (4)
注:
loadJson函数变成异步的。
所有的 .then 里面都换成了await。
我们可以返回response.json(),而不是等待它,像这样:
if (response.status == 200) {
return response.json(); // (3)
}
然后,外部代码将不得不等待这一承诺得到解决。在我们的情况下,这并不重要。
从loadJson抛出的错误由.catch处理。我们不能在这里使用await loadJson(…),因为我们不是在一个异步函数中。
Rewrite "rethrow" with async/await
下面是“重新抛出”的例子。用async/await代替.then/catch重写它。
并且在demoGithubUser中使用循环来摆脱递归:通过async/await,这变得很容易做到。
class HttpError extends Error {
constructor(response) {
super(`${response.status} for ${response.url}`);
this.name = 'HttpError';
this.response = response;
}
}
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
});
}
// Ask for a user name until github returns a valid user
function demoGithubUser() {
let name = prompt("Enter a name?", "iliakan");
return loadJson(`https://api.github.com/users/${name}`)
.then(user => {
alert(`Full name: ${user.name}.`);
return user;
})
.catch(err => {
if (err instanceof HttpError && err.response.status == 404) {
alert("No such user, please reenter.");
return demoGithubUser();
} else {
throw err;
}
});
}
demoGithubUser();
这里没有什么诀窍。只要把.catch换成try…在demoGithubUser中捕获并在需要的地方添加async/await:
class HttpError extends Error {
constructor(response) {
super(`${response.status} for ${response.url}`);
this.name = 'HttpError';
this.response = response;
}
}
async function loadJson(url) {
let response = await fetch(url);
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
}
// Ask for a user name until github returns a valid user
async function demoGithubUser() {
let user;
while(true) {
let name = prompt("Enter a name?", "iliakan");
try {
user = await loadJson(`https://api.github.com/users/${name}`);
break; // no error, exit loop
} catch(err) {
if (err instanceof HttpError && err.response.status == 404) {
// loop continues after the alert
alert("No such user, please reenter.");
} else {
// unknown error, rethrow
throw err;
}
}
}
alert(`Full name: ${user.name}.`);
return user;
}
demoGithubUser();
Call async from non-async
我们有一个“常规”函数叫做f。你如何调用异步函数wait()并在f内部使用它的结果?
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
return 10;
}
function f() {
// ...what should you write here?
// we need to call async wait() and wait to get 10
// remember, we can't use "await"
}
这个任务在技术上非常简单,但是对于刚接触async/await的开发人员来说,这个问题是很常见的。
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
return 10;
}
function f() {
// shows 10 after 1 second
wait().then(result => alert(result));
}
f();
评论