14 实现Ajax

步骤

  • 创建 XMLHttpRequest 实例
  • 发出 HTTP 请求
  • 服务器返回 XML 格式的字符串
  • JS 解析 XML,并更新局部页面
  • 不过随着历史进程的推进,XML 已经被淘汰,取而代之的是 JSON。

了解了属性和方法之后,根据 AJAX 的步骤,手写最简单的 GET 请求。

1 原生实现

    function ajax() {
      let xhr = new XMLHttpRequest() //实例化,以调用方法
      xhr.open('get', 'https://www.google.com')  //参数2,url。参数三:异步
      xhr.onreadystatechange = () => {  //每当 readyState 属性改变时,就会调用该函数。
        if (xhr.readyState === 4) {  //XMLHttpRequest 代理当前所处状态。
          if (xhr.status >= 200 && xhr.status < 300) {  //200-300请求成功
            let string = xhr.responseText
            //JSON.parse() 方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象
            let object = JSON.parse(string)
          }
        }
      }
      xhr.send() //用于实际发出 HTTP 请求。不带参数为GET请求
    }

2 Promise实现

基于Promise封装Ajax

  • 返回一个新的Promise实例
  • 创建HMLHttpRequest异步对象
  • 调用open方法,打开url,与服务器建立链接(发送前的一些处理)
  • 监听Ajax状态信息
  • 如果xhr.readyState == 4(表示服务器响应完成,可以获取使用服务器的响应了)
    • xhr.status == 200,返回resolve状态
    • xhr.status == 404,返回reject状态
  • xhr.readyState !== 4,把请求主体的信息基于send发送给服务器
    function ajax(url) {
      return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open('get', url)
        xhr.onreadystatechange = () => {
          if (xhr.readyState == 4) {
            if (xhr.status >= 200 && xhr.status <= 300) {
              resolve(JSON.parse(xhr.responseText))
            } else {
              reject('请求出错')
            }
          }
        }
        xhr.send()  //发送hppt请求
      })
    }
    
    let url = '/data.json'
    ajax(url).then(res => console.log(res))
      .catch(reason => console.log(reason))

补充(现代做法):现在业务里几乎不再手写 XMLHttpRequest,而是用 fetch(返回 Promise,需用 AbortController 取消、并自行处理 HTTP 错误码——fetch 只在网络失败时 reject,4xx/5xx 不会 reject)。面试若问「fetchXMLHttpRequest 的区别」可答:fetch 默认不带 cookie(需 credentials: 'include')、无原生超时(用 AbortSignal.timeout(ms))、无上传进度。

async function request(url, { timeout = 8000, ...opts } = {}) {
  const res = await fetch(url, { signal: AbortSignal.timeout(timeout), ...opts })
  if (!res.ok) throw new Error(`HTTP ${res.status}`) // fetch 不会因 4xx/5xx 而 reject
  return res.json()
}
Last Updated:
Contributors: leeguooooo