学习知识的目的,是让我们捕捉各种表象背后的本质,让我们走出下愚的死循环,步入到上智的境界。

Fetch 封装

fetch 本身不支持超时和 abort() 方法,下面的封装利用 Promiss.race 模拟超时,触发 Promiss 的 reject 来实现了abort()

function request(url, data, method = "GET", options = {}) {
  // key => value 转换成需要的格式
  let items = [];
  for (let key in data) {
    items.push([key, data[key]]);
  }
  const body = new URLSearchParams(items).toString();

  // 组装参数
  let params = {
    method: method,
  };
  if (method === "GET") {
    // 如果是GET请求,拼接url
    url += "?" + body;
  } else {
    params.body = body;
  }

  // 携带cookie
  if (options.cookie != undefined) {
    params.credentials = "include";
  }
  if (options.headers != undefined && typeof options.headers == "object") {
    params.headers = new Headers(options.headers);
  } else {
    params.headers = new Headers({
      Accept: "application/json",
      "Content-Type": "application/x-www-form-urlencoded",
    });
  }
  const fetchPromise = fetch(url, params)
    .then((r) => {
      //处理http状态
      if (r.status >= 200 && r.status < 300) {
        return r;
      }
      const error = new Error(r.statusText);
      error.response = r;
      throw error;
    })
    .then((r) => (options.dataType == "text" ? r.text() : r.json()))
    .then((r) => r);
  // 强制取消
  fetchPromise.abort = function (resolve, reject) {
    reject(new Error("fetch abort"));
  };
  if (options.timeout == undefined) {
    return fetchPromise;
  }
  // 模拟超时
  const timeoutPromise = new Promise(function (resolve, reject) {
    setTimeout(() => {
      reject(new Error("fetch timeout"));
    }, options.timeout);
  });
  return Promise.race([fetchPromise, timeoutPromise]);
}

export function get(url, data, options = {}) {
  return request(url, data, "GET", options);
}

export function post(url, data, options = {}) {
  return request(url, data, "POST", options);
}

 调用方法

post("/api/test",{ title: "标题" },{
    dataType: "json",
    cookie: true,
    headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
 });