javascript封装可中止的fetch

封装 fetch

// 请求配置类型,后续可扩展
interface RequestConfig {
  // 基础请求地址
  baseUrl?: string;
  // 超时时间
  timeout?: number;
}

// 请求返回值类型
// 在Promise基础上增加 abortController 属性,可用于手动终止请求
export interface RequestReturn extends Promise<Response> {
  abortController: AbortController;
}

// 重新声明请求类型,在 fetch 默认的 input、init 属性基础上增加了 config 属性,返回值在 Promise 基础上增加了 abortController 属性
interface Request {
  (
    input: RequestInfo,
    init?: RequestInit,
    config?: RequestConfig
  ): RequestReturn;
  create?: any;
}

// 直接调用,该形式类似直接使用 axios
const request: Request = (input, init?, config?) => {
  const controller = new AbortController();
  const signal = controller.signal;
  setTimeout(
    () => {
      controller.abort();
    },
    // 默认10秒超时
    config?.timeout !== null && config?.timeout !== undefined
      ? config?.timeout
      : 10000
  );
  // 由于js只能声明函数,而不能直接声明可调用对象,故使用 Object.assign 的方式将属性与函数整合在一起
  return Object.assign(
    fetch((config?.baseUrl || "") + input, { signal, ...init }),
    { abortController: controller }
  );
};

// 创建实例,该形式类似使用 axios.create 创建实例
request.create = (config: RequestConfig) => {
  const request: Request = (input, init?, instanceConfig?) => {
    const controller = new AbortController();
    const signal = controller.signal;
    setTimeout(() => {
      controller.abort();
    }, instanceConfig?.timeout || config.timeout || 10000);
    return Object.assign(
      fetch((instanceConfig?.baseUrl || config.baseUrl || "") + input, {
        signal,
        ...init,
      }),
      { abortController: controller }
    );
  };
  return request;
};

export default request;

使用封装后的 fetch

import request from "./api";

/**
 * 直接使用,声明请求
 */
const getXXXData = request(
  "/baseUrl/xxx",
  {
    method: "POST",
    body: {
      param1: "param1",
      param2: "param2",
    },
    headers: new Headers({
      "Content-Type": "application/json",
    }),
  },
  {
    timeout: 5000,
  }
);

/**
 * 创建实例,再声明请求
 */
const xxxRequest = request.create({
  baseUrl: "/baseUrl",
  timeout: 5000,
});
const getXXXData = xxxRequest("/xxx", {
  method: "POST",
  body: {
    param1: "param1",
    param2: "param2",
  },
  headers: new Headers({
    "Content-Type": "application/json",
  }),
});

// 某些条件下,手动终止请求(如页面切换,但请求还未返回)
getXXXData.abortController.abort();

// 获取请求结果
getXXXData
  .then((res) => {
    return res.json();
  })
  .then((res) => {
    console.log(res);
  })
  .error(console.error);

参考资料

Abortable fetch