考察点分析

该题目主要考察以下核心能力:

  1. 异步通信机制:对浏览器端异步请求实现原理的理解
  2. XHR对象掌握:XMLHttpRequest生命周期管理及API使用熟练度
  3. 健壮性编程:错误边界处理、超时控制等生产环境必备能力

具体技术评估点:

  • XMLHttpRequest对象初始化与状态管理
  • GET/POST请求参数处理差异
  • 跨浏览器事件绑定与错误处理
  • 超时机制实现与异常熔断
  • 响应数据反序列化处理

技术解析

关键知识点

XMLHttpRequest > 异步事件处理 > 请求参数序列化 > HTTP状态码校验

原理剖析

  1. XHR工作流程

    • 创建XHR实例(new XMLHttpRequest()
    • 初始化请求(open(method, url)
    • 绑定事件监听器(onload/onerror/ontimeout)
    • 发送请求(send(body)
  2. 事件触发逻辑

    • onload:请求完成时触发(包括HTTP错误状态)
    • onerror:网络层异常时触发
    • ontimeout:超过指定时限未响应时触发
  3. 常见误区

    • 混淆网络错误与HTTP错误状态码处理
    • GET请求参数未正确编码导致特殊字符丢失
    • 未正确设置POST请求的Content-Type头部

问题解答

XMLHttpRequest工作原理

XMLHttpRequest通过浏览器提供的API实现客户端与服务器的异步通信。其工作流程分为四个阶段:1)创建实例初始化请求 2)配置请求方法和URL 3)设置回调监听网络事件 4)发送请求并处理响应。核心在于通过事件驱动模型处理异步操作,利用readyState跟踪请求状态。

实现代码

  function ajax({
  method = 'GET',
  url,
  data = null,
  headers = {},
  timeout = 5000
} = {}) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    
    // 处理GET查询参数
    if (method === 'GET' && data) {
      const encodedParams = new URLSearchParams(data).toString()
      url = `${url}${url.includes('?') ? '&' : '?'}${encodedParams}`
    }

    xhr.open(method, url, true)

    // 设置请求头
    Object.entries(headers).forEach(([key, value]) => {
      xhr.setRequestHeader(key, value)
    })

    // 超时设置
    xhr.timeout = timeout
    xhr.ontimeout = () => reject(new Error('Request timeout'))

    // 响应处理
    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        try {
          const response = xhr.responseText ? JSON.parse(xhr.responseText) : null
          resolve(response)
        } catch (e) {
          reject(new Error('JSON parse error'))
        }
      } else {
        reject(new Error(`HTTP Error ${xhr.status}`))
      }
    }

    // 网络错误处理
    xhr.onerror = () => reject(new Error('Network failure'))

    // 处理POST数据
    let body = null
    if (method === 'POST') {
      const contentType = headers['Content-Type']
      if (data instanceof FormData) {
        body = data
      } else if (contentType?.includes('application/json')) {
        body = JSON.stringify(data)
      } else {
        body = new URLSearchParams(data).toString()
      }
    }

    xhr.send(body)
  })
}
  

解决方案

代码优化点

  1. 参数序列化:自动处理对象到查询字符串的转换
  2. 错误隔离:使用try-catch防止响应解析异常
  3. 类型安全:区分FormData/JSON/表单编码等格式

扩展建议

  • 性能优化:增加请求中止控制(AbortController)
  • 缓存策略:为GET请求添加cache-busting机制
  • 重试机制:对超时请求进行有限次数重试

深度追问

  1. 如何实现请求中断? 使用AbortController绑定signal到XHR

  2. Fetch API与XHR主要区别? Fetch基于Promise,更简洁的API设计

  3. 如何监控上传进度? 监听xhr.upload.onprogress事件

Last updated 06 Mar 2025, 13:07 +0800 . history