用async/await使用Fetch函数的教程
如何用async/await使用Fetch
Fetch API是在Web应用程序中进行网络的默认工具。虽然fetch()
一般来说很容易使用,但也有一些细微差别需要注意。
在这篇文章中,你会发现如何使用fetch()
与async/await
语法的常见场景。你将了解如何获取数据、处理获取错误、取消获取请求,以及更多。
目录
1.fetch() 的介绍
Fetch API在网络上访问资源。你可以进行HTTP请求(使用GET
,POST
和其他方法),下载和上传文件。
要开始一个请求,请调用特殊函数fetch()
。
const response = await fetch(resource[, options]);
它接受两个参数:
fetch()
开始一个请求并返回一个承诺。当请求完成时,该承诺被Response对象解析。如果由于某些网络问题导致请求失败,则拒绝该承诺。
async/await
语法非常适用于fetch()
,因为它简化了承诺的工作。
例如,让我们做一个请求来获取一些电影。
async function fetchMovies() {
const response = await fetch('/movies');
// waits until the request completes...
console.log(response);
}
fetchMovies()
是一个异步函数,因为它被标记为async
关键字。
await fetch('/movies')
开始一个HTTP请求到'/movies'
URL。因为await
关键字的存在,异步函数被暂停,直到请求完成。
当请求完成后,response
,并分配给请求的响应对象。让我们在下一节看看如何从响应中提取有用的数据,如JSON或纯文本。
2.取出JSON
response
对象,由await fetch()
返回,是一个通用的占位符,用于多种数据格式。
例如,你可以从一个获取响应中提取JSON对象。
async function fetchMoviesJSON() {
const response = await fetch('/movies');
const movies = await response.json();
return movies;
}
fetchMoviesJSON().then(movies => {
movies; // fetched movies
});
response.json()
是Response对象的一个方法,让你从响应中提取一个JSON对象。该方法返回一个承诺,所以你必须等待JSON: 。await response.json()
响应对象提供了很多有用的方法(都返回承诺):
response.json()
返回一个解析为JSON对象的承诺response.text()
返回一个解析为原始文本的承诺response.formData()
返回一个解析为FormData的承诺response.blob()
返回一个解析为Blob(原始数据的类文件对象)的承诺response.arrayBuffer()()
返回一个解析为ArryBuffer(原始的通用二进制数据)的承诺。
3.处理获取错误
当我在熟悉fetch()
,我很惊讶,当服务器返回一个糟糕的HTTP状态时,fetch()
并没有抛出一个错误,例如客户端(400–499
)或服务器错误(500–599
)。
例如,让我们访问服务器上一个不存在的页面'/oops'
。正如预期的那样,这种请求以404
响应状态结束。
async function fetchMovies404() {
const response = await fetch('/oops');
response.ok; // => false
response.status; // => 404
const text = await response.text();
return text;
}
fetchMovies404().then(text => {
text; // => 'Page not found'
});
当获取URL'/oops'
时,服务器响应的状态是404
,文本是'Page not found'
。令人惊讶的是,fetch()
并没有因为缺少URL而产生错误,而是认为这是一个完成的HTTP请求。
fetch()
只有在无法提出请求或无法检索到响应时才会拒绝。这可能是由于网络问题而发生的:没有网络连接,找不到主机,服务器没有响应。
幸运的是,response.ok
属性可以让你区分好的和坏的HTTP响应状态。只有当响应的状态是200-299
,该属性才会被设置为true
。
在上面的例子中,response.ok
属性是false
,因为响应的状态是404
。
如果你想在一个坏的HTTP状态下抛出一个错误(在200-299
范围之外),检查response.ok
属性的值并手动抛出一个错误。
async function fetchMoviesBadStatus() {
const response = await fetch('/oops');
if (!response.ok) {
const message = `An error has occured: ${response.status}`;
throw new Error(message);
}
const movies = await response.json();
return movies;
}
fetchMoviesBadStatus().catch(error => {
error.message; // 'An error has occurred: 404'
});
4.取消一个获取请求
不幸的是,fetch()
API本身不允许在开始后取消一个获取请求。要取消一个获取请求,你需要一个额外的工具AbortController。
连接fetch()
和AbortController
需要 3 个步骤。
// Step 1: instantiate the abort controller
const controller = new AbortController();
// Step 2: make the fetch() aware of controller.signal
fetch(..., { signal: controller.signal });
// Step 3: call to cancel the request
controller.abort();
A) 在开始请求之前,创建一个中止控制器实例:controller = new AbortController()
。
B) 当正确启动请求时,使用fetch(url, { signal: controller.signal })
的选项参数,并将signal
属性设置为controller.signal
。
C)最后,如果你需要取消请求,只需调用controller.abort()
方法。
例如,让我们实现2个按钮来控制一个获取请求。点击按钮Fetch movies开始一个fetch()
请求,而点击Cancel fetch中止正在进行的请求。
let controller = null;
fetchMoviesButton.addEventListener('click', async () => {
controller = new AbortController();
try {
const response = await fetch('/movies', {
signal: controller.signal
});
} catch (error) {
console.log('Fetch error: ', error);
}
controller = null;
});
cancelFetchButton.addEventListener('click', () => {
if (controller) {
controller.abort();
}
});
打开演示。点击Fetch movies来启动请求,然后马上点击Cancel fetch来取消请求。这使得活动的请求被取消:await fetch()
被拒绝,抛出一个中止错误。然后catch
块捕捉到中止错误。
终止控制器实例是不可重复使用的。每次你启动一个fetch()
请求,你必须为每个请求创建一个新的中止控制器实例。
顺便提一下,如果你想对fetch()
请求进行超时处理,请关注我的文章《如何对fetch()请求进行超时处理》。
5.平行获取请求
要执行平行的获取请求,请使用Promise.all()辅助函数。
让我们开始2个平行请求来获取电影和类别。
async function fetchMoviesAndCategories() {
const [moviesResponse, categoriesResponse] = await Promise.all([
fetch('/movies'),
fetch('/categories')
]);
const movies = await moviesResponse.json();
const categories = await categoriesResponse.json();
return [movies, categories];
}
fetchMoviesAndCategories().then(([movies, categories]) => {
movies; // fetched movies
categories; // fetched categories
}).catch(error => {
// /movies or /categories request failed
});
await Promise.all([...])
开始平行地获取请求,并等待所有的请求被解决。
如果有任何请求失败,那么整个并行请求就会立即被拒绝,并出现失败的请求错误。
转载自:https://juejin.cn/post/7126441823584649224