Promise 封装 setTimeout 和 XMLHttpRequest 的核心是用 resolve/reject 显式暴露异步操作的完成状态,使调用方可统一用 .then()/.catch() 或 await 处理;setTimeout 封装实现可控延迟,XMLHttpRequest 封装替代分散回调并规范错误处理,而 fetch 作为原生 Promise API 更推荐优先使用。

用 Promise 封装 setTimeout 或传统 AJAX(如 XMLHttpRequest)的核心思路是:把异步操作的“开始”和“结束”(成功/失败)通过 resolve 和 reject 显式暴露出来,让调用方能用 .then()、.catch() 或 await 统一处理。
封装 setTimeout:创建可控的延迟 Promise
原生 setTimeout 只是延时执行回调,不返回可链式处理的值。封装后可轻松实现“等待 X 毫秒再继续”:
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
// 使用示例
delay(1000).then(() => console.log('1秒后执行'));
// 或配合 async/await
async function doSomething() {
console.log('开始');
await delay(1500);
console.log('1.5秒后继续');
}
进阶可支持传值或取消(需额外控制逻辑),但基础封装只需一行 resolve 即可。
封装 XMLHttpRequest:替代老旧回调写法
传统 XMLHttpRequest 需手动监听 onload、onerror,且错误分支分散。用 Promise 封装后结构清晰:
function request(url, options = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(options.method || 'GET', url);
// 设置请求头(如需)
if (options.headers) {
Object.keys(options.headers).forEach(key => {
xhr.setRequestHeader(key, options.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('Network error'));
xhr.ontimeout = () => reject(new Error('Request timeout'));
xhr.timeout = options.timeout || 0;
xhr.send(options.body || null);
});
}
// 使用示例
request('/api/data')
.then(data => console.log('获取成功:', data))
.catch(err => console.error('出错了:', err.message));
// 或 await 写法
async function fetchData() {
try {
const result = await request('/api/user', { method: 'POST', body: JSON.stringify({ id: 1 }) });
console.log(result);
} catch (err) {
console.warn('请求失败', err);
}
}
注意:xhr.response 默认是字符串,如需自动解析 JSON,可在 resolve 前加 JSON.parse(xhr.response)(并捕获解析异常)。
更现代的选择:优先用 fetch + Promise(无需手动封装)
fetch 本身就是基于 Promise 的 API,比封装 XMLHttpRequest 更简洁:
// fetch 已是 Promise,但默认不拒绝 HTTP 错误状态
function apiGet(url) {
return fetch(url)
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json(); // 自动解析 JSON
});
}
// 或更健壮的写法(统一错误处理)
async function safeFetch(url) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return await res.json();
} catch (err) {
throw new Error(`API 请求失败: ${err.message}`);
}
}
除非需要兼容极老浏览器(如 IE),否则直接用 fetch 是更轻量、标准的做法。
小结:封装的关键点
-
Promise 构造器内必须调用
resolve或reject,否则 Promise 会一直 pending -
setTimeout封装只关心“时机”,通常只用resolve;AJAX 封装必须区分成功响应与网络/HTTP 错误,并分别调用resolve/reject - 错误应尽量包装成
Error实例,便于后续用instanceof Error判断或统一日志处理 - 避免在 Promise 中遗漏
onerror、ontimeout等边界情况,否则错误可能静默丢失


















