Promise 封装 XMLHttpRequest 是实现轻量 Ajax 工具的核心:通过返回 Promise 的 request 函数统一处理 onload/onerror,自动解析 JSON、支持超时/取消/错误分类,并导出 get/post/put/delete 语义化方法。

用 Promise 封装 XMLHttpRequest 是实现现代、可链式调用的轻量 Ajax 工具的核心思路:把原生异步请求包装成返回 Promise 的函数,让成功/失败逻辑更清晰、更易组合。
基础封装:一个通用的 request 函数
核心是创建一个返回 Promise 的函数,内部用 XMLHttpRequest 发起请求,并在 onload / onerror 中 resolve 或 reject。
- 手动设置请求方法、URL、请求头
- 监听
load事件判断状态码(2xx 视为成功) - 监听
error、timeout、abort等异常情况统一 reject - 响应体自动解析为 JSON(若 Content-Type 包含
application/json),否则保留为字符串
示例代码:
function request(url, options = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const { method = 'GET', headers = {}, timeout = 10000, body } = options;
xhr.open(method.toUpperCase(), url);
xhr.timeout = timeout;
// 自动设置 Content-Type(仅 POST/PUT 等有 body 时)
if (body && !headers['Content-Type']) {
xhr.setRequestHeader('Content-Type', 'application/json');
}
// 设置其他请求头
Object.keys(headers).forEach(key => {
xhr.setRequestHeader(key, headers[key]);
});
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
const contentType = xhr.getResponseHeader('content-type') || '';
let data;
try {
data = contentType.includes('application/json')
? JSON.parse(xhr.responseText)
: xhr.responseText;
} catch (e) {
reject(new Error('JSON parse error'));
return;
}
resolve({ data, status: xhr.status, statusText: xhr.statusText });
} else {
reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));
}
};
xhr.onerror = () => reject(new Error('Network error'));
xhr.ontimeout = () => reject(new Error('Request timeout'));
xhr.onabort = () => reject(new Error('Request aborted'));
xhr.send(body ? JSON.stringify(body) : null);
});
}
封装常用 HTTP 方法:get / post / put / delete
基于 request 函数,导出语义化方法,减少重复传参,提升调用体验。
立即学习“Java免费学习笔记(深入)”;
- get:默认 method='GET',参数拼接在 URL 后(支持对象自动序列化)
- post:默认发送 JSON,body 直接作为 payload
- 其余方法类似,保持接口一致
简单辅助函数示例(含 URL 参数序列化):
function serialize(obj) {
return Object.keys(obj)
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`)
.join('&');
}
export const get = (url, params = {}) => {
const query = serialize(params);
const finalUrl = query ? `${url}?${query}` : url;
return request(finalUrl, { method: 'GET' });
};
export const post = (url, data = {}) =>
request(url, { method: 'POST', body: data });
export const put = (url, data = {}) =>
request(url, { method: 'PUT', body: data });
export const del = (url) =>
request(url, { method: 'DELETE' });
支持取消请求(AbortController 兼容方案)
XMLHttpRequest 原生不支持标准 AbortController,但可通过 xhr.abort() 模拟取消逻辑。可在 Promise 外层加一层 cancelable 包装。
- 返回一个带
cancel()方法的对象 - 调用 cancel 时触发 xhr.abort(),并 reject 一个特定错误
- 注意:已响应的请求无法取消,只能中断未完成传输
增强版 request 示例:
function requestCancelable(url, options = {}) {
const xhr = new XMLHttpRequest();
let isAborted = false;
const promise = new Promise((resolve, reject) => {
xhr.onload = () => {
if (isAborted) return;
// ... 同上处理逻辑
};
xhr.onerror = () => !isAborted && reject(new Error('Network error'));
xhr.ontimeout = () => !isAborted && reject(new Error('Timeout'));
xhr.onabort = () => reject(new Error('Canceled'));
xhr.open(options.method || 'GET', url);
xhr.timeout = options.timeout || 10000;
// ... 设置 header 和 send
});
return {
promise,
cancel() {
isAborted = true;
xhr.abort();
}
};
}
使用示例与错误处理建议
实际调用时推荐配合 try/catch 或 .catch() 统一处理异常,避免未捕获 rejection。
- 成功时解构响应对象:
{ data, status } - 服务端业务错误(如 400/500)已在 Promise reject 中抛出,需主动捕获
- 可配合 loading 状态、重试逻辑、请求拦截(如 token 注入)进一步扩展
调用示例:
async function fetchData() {
try {
const res = await get('/api/users', { page: 1 });
console.log(res.data); // ✅
} catch (err) {
console.error('请求失败:', err.message); // ❌
}
}
// 链式调用
post('/api/login', { username: 'a', password: 'b' })
.then(res => console.log(res.data))
.catch(err => alert(err.message));
不复杂但容易忽略细节:状态码判断、JSON 安全解析、超时控制、请求头自动适配、取消能力——把这些补全,就是一个真正可用的轻量 Ajax 工具。


















