添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
月球上的汤圆  ·  【samsung S23 ...·  2 月前    · 
乖乖的冰棍  ·  Invoke-WebRequest ...·  1 年前    · 
月之
关注前端编码,想要学习开发 Java, Windows App, iOS App.
如何与 async/await 一起使用 Fetch

如何与 async/await 一起使用 Fetch

Fetch API 已经成为前端应用中获取资源的原生方式。

在这篇文章中,我将展示如何用 async/await 语法使用 Fetch API 的常见场景。目的是让你对如何获取数据、处理获取错误、取消获取请求等有信心。

开始之前,推荐熟悉 async/await 语法。在下面的例子中将广泛使用它。

fetch() 简介

Fetch API 通过网络访问资源。通过创建 HTTP 请求(GET,POST),下载和上传文件。

开始请求时,执行规范函数 fetch()

const response = await fetch(resource[, options]);

该函数接收两个参数:

  • resource :一个 URL 字符串,或者一个 Request 对象;
  • options :一个配置对象,对象 包含 method 'GET'' 'POST'' ), headers body credentials 等等属性,更多 属性参数

执行 fetch() 启动一个请求并返回一个承诺。当请求完成后,用 Response 解决承诺。如果由于一些网络问题导致请求失败,则拒绝该承诺。

async/await 语法非常适合 fetch() ,因为它简化了对承诺的工作。

例如,让我们做一个获取一些电影的请求:

async function fetchMovies() {
  const response = await fetch('/movies');
  // 等待直到请求完成
  console.log(response);
}

fetchMovies() 是一个异步函数,因为它用 async 关键字标记。

await fetch('/movies') 开始向 '/movies' URL 发出 HTTP 请求。由于存在 await 关键字,异步函数被暂停,直到请求完成。

当请求完成后,响应会被分配给请求的响应对象。让我们在下一节看看如何从响应中提取有用的数据,如 JSON 或纯文本。

请求 JSON 数据

fetch() 返回的 Response 对象是多种数据格式的通用占位符。下面是你如何从响应对象中以 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 对象。该方法返回一个 promise,所以你必须等待 JSON 结果返回: await response.json()

response 对象提供了很多有用的方法:

  • response.json() 返回一个解析为 JSON 对象的 promise;
  • response.text() 返回一个解析为文本内容的 promise;
  • response.formData 返回一个解析为 FormData 对象的 promise;
  • response.blob() 返回一个解析为 Blog 的 promise;
  • response.arrayBuffer() 返回一个解析为 ArrayBuffer 的 promise。

处理 fetch 错误

当我在了解 fetch() 的时候,我很惊讶,当服务器返回一个不好的 HTTP 状态时,比如 404 502 fetch() 不会抛出一个错误。

让我们尝试访问服务器上一个不存在的页面 '/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'
});

取消 fetch 请求

为了取消一个 丰田车请求,你需要添加 AbortController 工具。使用 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();

在下面的例子中,但点击按钮 “Cancel” 时,一个 fetch() 请求被取消:

async function fetchMoviesWithCancel(controller) {
  const response = await fetch('/movies', {
    signal: controller.signal,
  });
  const movies = await response.json();
  return movies;
const controller = new AbortController();
cancelButton.addEventListener('click', () => {
  controller.abort();
});
fetchMoviesWithCancel(controller).catch((error) => {
  error.name; // => 'AbortError'
});

const controller = new AbortController() 创建一个 AbortController 的实例。然后 controller.signal 属性最为 fetch 请求的参数: fetch(..., { signal: controller.signal })

controller.abort() 在按钮的点击事件函数中被执行时,取消请求。

当 fetch 请求被取消, fetch() 函数失败并返回拒绝错误(AbortError)的 promise。

并发 fetch 请求

执行 Promise.all() 函数发起并发 fetch 请求。让我们并发请求电影和分类的两个接口:

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
});

await Promise.all([...]) 并发开始 fetch 请求,并等待直到所有的请求完成。

拦截 fetch 请求

有时候,你可能需要在发送请求之前,或者在收到响应之后进行工作:这被命名为拦截。

拦截的一个例子是 处理 fetch 错误 :如果响应状态不在 200 299 的范围内,抛出一个错误。

fetch() API 并没有提供任何拦截请求的功能。这是可以理解的,因为 fetch() API 设计得很简单。

decorator 模式 是设计拦截 fetch() 请求的一个很好的解决方案。让我们试着使用它。

首先,定义一个有 doFetch() 方法的类 Fetcher() (它只是简单地调用 fetch() 函数):

class Fetcher {
  doFetch(resource, options) {
    return fetch(resource, options);
}

然后让我们创建类 Fetcher 的实例,并使用它请求电影列表:

const fetcher = new Fetcher();
async function fetchMoviesBadStatus() {
  const response = await fetcher.doFetch('/movies');
  if (!response.ok) {
    const message = `An error has occured: ${response.status}`;
    throw new Error(message);
  const movies = await response.json();
  return movies;
fetchMoviesBadStatus()
  .then((movies) => {
    // When fetch succeeds
    movies;
  .catch((error) => {
    // When fetch ends with a bad http status
    error.message;
  });

不直接调用 Fetch API,而是实例化 fetcher const fetcher = new Fetcher() ,然后调用 await fetcher.doFetch('/movies') 开始请求。

if 语句 if (!response.ok) { ......} 里面的逻辑是:如果响应状态在 200 299 范围之内,就会抛出一个错误。这个逻辑应该重构成一个拦截器,因为它对响应进行修改。让我们把这个逻辑移到一个装饰器中, FetchDecoratorBadStatus

class FetchDecoratorBadStatus {
  decoratee;
  constructor(decoratee) {
    this.decoratee = decoratee;
  async doFetch(resource, options) {
    const response = await this.decoratee.doFetch(resource, options);
    if (!response.ok) {
      const message = `An error has occured: ${response.status}`;
      throw new Error(message);
    return response;
}

FetchDecoratorBadStatus 封装了一个 Fetcher 实例( decoratee 属性)。 decoratee doFetch() 方法调用 this.decoratee.doFetch(resource, options) ,之后做出 if(!response.ok) { .... } 状态检查(拦截)。

由于将错误拦截逻辑移到 FetchDecoratorBadStatus fetchMoviesBadStatus() 可以被简化:

const fetcher = new FetchDecoratorBadStatus(new Fetcher());
async function fetchMoviesBadStatus() {
  const response = await fetcher.doFetch('/movies');
  const movies = await response.json();
  return movies;
fetchMoviesBadStatus()
  .then((movies) => {
    // When fetch succeeds
    // 当请求成功
    movies;
  .catch((error) => {