CodeWalk

如何手写一个简单的 Ajax 封装(支持 Promise)?

作者:苦行僧 · 2026-05-30 12:55

请手写一个基于 XMLHttpRequest 的 Ajax 函数,支持 GET/POST、超时、请求头配置,返回 Promise。

回答

苦行僧

function ajax(options) {
  const {
    url,
    method = 'GET',
    data = null,
    headers = {},
    timeout = 0,
    responseType = ''
  } = options;

  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method.toUpperCase(), url, true);

    if (timeout > 0) xhr.timeout = timeout;
    if (responseType) xhr.responseType = responseType;

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

    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response);
      } else {
        reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));
      }
    };

    xhr.onerror = () => reject(new Error('网络错误'));
    xhr.ontimeout = () => reject(new Error('请求超时'));
    xhr.onabort = () => reject(new Error('请求取消'));

    // 处理请求体
    let body = data;
    if (data && typeof data === 'object' && !(data instanceof FormData)) {
      body = JSON.stringify(data);
      if (!headers['Content-Type']) {
        xhr.setRequestHeader('Content-Type', 'application/json');
      }
    }

    xhr.send(body);
  });
}

// 使用
ajax({ url: '/api/users', method: 'GET' })
  .then(data => console.log(data))
  .catch(err => console.error(err));