day4.2_手写ajax

114 阅读1分钟
  • xhr中的readyState状态
    • 0:请求未初始化,还没有调用open
    • 1:请求已经建立,但还没有发送,还没有调用send
    • 2:请求已经发送,正在处理中(通常现在可以从响应中获取内容头)
    • 3:请求在处理中,通常响应中已有部分数据可用了,但没有全部完成
    • 4:响应已经完成,可以获取并使用服务器的响应了
  • ie浏览器中的get请求,会对url进行判断,若与上一次的请求一致,则会直接从缓存中拿数据返回,即使服务器数据已经更新
    • 故可以采用通过添加时间戳的方法来兼容ie
  function ajax(options) {
    const {
      type = "get",
      data = {},
      timeout = null,
      url,
      success = function () {},
      error = function () {},
    } = options;
    // 获取xhr
    let xhr = null;
    let timer = null;

    function getObjtoStr(data = {}) {
      data.t = new Date().getTime();
      const arr = [];
      for (let key in data) {
        if (data.hasOwnProperty(key)) {
          arr.push(
            `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`
          );
        }
      }
      return arr.join("&");
    }

    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      // 兼容ie Microsoft
      xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    // 发送请求
    if (type.toLowerCase() == "get") {
      const str = getObjtoStr(data);
      xhr.open(type, url + "?" + str, true);
      xhr.send();
    } else {
      xhr.open(type, url, true);
      // 设置请求头
      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      xhr.send;
    }

    // 监听请求
    xhr.onreadystatechange = () => {
      if (timer) {
        clearInterval(timer);
        timer = null;
      }
      if (xhr.readyState === 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
          success(xhr.resopnseText);
        } else {
          error(xhr.resopnseText);
        }
      }
    };
    // 请求超时
    if (timeout) {
      timer = setInterval(() => {
        xhr.abort();
        clearInterval(timer);
        timer = null;
      }, timeout);
    }
  }