#2 Fetch API

2022-08-02

在很长一段时间里,浏览器发送 Ajax 请求主要依赖 XMLHttpRequest,也就是大家熟悉的 XHR。
但随着 JavaScript 生态的发展,XHR 的一些问题越来越明显:

  • 代码太啰嗦
  • 回调层级复杂
  • 错误处理麻烦
  • 可读性较差

于是浏览器推出了更现代、更简洁的网络请求方案 Fetch API。

XMLHttpRequest 的问题

先看一个传统 Ajax 请求:

var xhr = new XMLHttpRequest();
xhr.open("GET", "/api/user", true);
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4) {
    if (xhr.status == 200) {
      console.log(xhr.responseText);
    }
  }
};
xhr.send();

虽然功能没问题,但存在几个明显缺点:

  1. 状态判断复杂:必须反复判断 readyState 和 status,初学者经常搞混。
  2. 回调代码较多:所有逻辑都写在 onreadystatechange 里面,代码一多就会非常乱。
  3. 服务器返回 JSON 时需要手动转换。
    JSON.parse(xhr.responseText)
    

Fetch 的基本写法

主要是基于 Promise 实现,可以链式调用,不用一层又一层地回调,更符合现代 JavaScript 风格。
注意:这是较新的语法,在某些老版本浏览器上可能支持程度不好,如果需要兼容,可以使用 XHR 或者 Axios、jQuery Ajax 等库。

fetch("/api/user")
  .then(function (response) { // Response 对象
    return response.json();
  })
  .then(function (data) {
    console.log(data);
  })
  .catch(function (error) { // 异常处理
    console.log(error);
  });

相比 XMLHttpRequest:

  • 代码明显更短
  • 结构更清晰
  • 更容易阅读

Fetch 也支持提交数据:

fetch("/api/user", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "Tom",
    age: 18
  })

})
.then(function (response) {
  return response.json();
})
.then(function (data) {
  console.log(data);
});

参考资料与拓展阅读

#1 Ajax

2011-05-12

Ajax 是一种让网页“不用刷新页面,也能和服务器通信”的技术。

比如:

  • 搜索框自动提示
  • 点赞后数字立即变化
  • 提交表单后局部刷新

这些功能背后通常都用了 Ajax。

什么是 Ajax?

Ajax 全称 Asynchronous JavaScript and XML,意思是 JS 异步请求服务器数据,虽然名字里有 XML,但实际开发里更多使用 JSON。

传统网页的工作流程:

  1. 点击按钮
  2. 浏览器请求服务器
  3. 服务器返回完整页面
  4. 浏览器整体刷新

问题:

  • 页面会闪一下
  • 速度较慢
  • 用户体验不好
  • 浪费带宽

Ajax 出现后:

  • 页面无需整体刷新
  • 后台获取数据
  • 只更新局部区域
  • 交互体验更流畅

Ajax 的实现方式

  1. 创建 XMLHttpRequest 对象
  2. 配置请求
  3. 发送请求
  4. 等待服务器响应
  5. 更新页面内容

GET 获取数据

function loadUser() {
  // 创建 XMLHttpRequest 对象
  var xhr = new XMLHttpRequest();

  // 配置请求
  xhr.open("GET", "/api/user", true);

  // 监听状态变化
  xhr.onreadystatechange = function () {
    // 请求完成
    if (xhr.readyState == 4) {
      // 请求成功
      if (xhr.status == 200) {
        // 输出服务器返回的数据
        console.log(xhr.responseText);
      } else {
        console.log("请求失败");
      }
    }
  };

  // 发送请求
  xhr.send();
}

POST 提交数据

function submitData() {
  var xhr = new XMLHttpRequest();

  xhr.open("POST", "/api/user", true);

  // 设置请求头
  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4 && xhr.status == 200) {
      console.log("提交成功");
    }
  };

  // 提交数据
  xhr.send("name=Tom&age=18");
}

IE 浏览器兼容

IE6/IE7 需要使用:

ActiveXObject;