如何实现可复用的异步XMLHttpRequest函数,按顺序执行请求并等待响应
问题根源
XMLHttpRequest为异步执行模型,onreadystatechange回调函数的返回值无法传递给外层getRequest函数,getRequest在执行xr.send()后会直接返回,不会等待请求完成,因此拿到的temp为undefined。
改造方案:用Promise封装通用请求函数
该方案完全不会破坏函数复用性,通用的请求逻辑全部封装在底层,不同请求的业务处理逻辑可以完全独立编写,同时天然支持等待请求完成、按顺序发起多个请求的需求,不需要自行实现变量监听逻辑。
function getRequest(URL) { const akey = '000'; // 返回Promise实例,外部可通过await/then等待结果 return new Promise((resolve, reject) => { const xr = new XMLHttpRequest(); xr.open("GET", URL); xr.setRequestHeader("X-API-Key", akey); xr.onreadystatechange = () => { if (xr.readyState === 4) { // 请求成功状态判断 if (xr.status >= 200 && xr.status < 300) { try { const xh = JSON.parse(xr.responseText); resolve(xh); // 将请求结果抛给外层调用方 } catch (e) { reject(new Error('响应数据解析失败')); } } else { reject(new Error(`请求失败,状态码:${xr.status}`)); } } }; // 网络异常捕获 xr.onerror = () => reject(new Error('网络请求异常')); xr.send(); }); }
调用方式
方式1:async/await语法(更适合顺序请求场景)
通用请求逻辑全部封装在getRequest内,业务处理逻辑独立编写,不存在复用性被破坏的问题:
async function BClick(){ try { const rqURL = 'https://endpoint'; // 等待请求完成后再执行后续代码 const temp = await getRequest(rqURL); console.log(temp); // 此处编写当前请求的专属处理逻辑 } catch (e) { // 统一处理请求错误 console.error(e.message); } }
如果需要按顺序发起多个请求,依次执行await即可:
async function sequentialRequest() { // 第一个请求完成后才会发起第二个请求 const statisticsData = await getRequest('统计数据API地址'); // 处理统计数据逻辑 const bagData = await getRequest('背包库存API地址'); // 处理背包数据逻辑 }
方式2:then链调用(适合回调风格场景)
function BClick(){ const rqURL = 'https://endpoint'; getRequest(rqURL) .then(temp => { console.log(temp); // 此处编写当前请求的专属处理逻辑 }) .catch(e => { console.error(e.message); }); }
顺序发起多个请求的写法:
function sequentialRequest() { getRequest('统计数据API地址') .then(statisticsData => { // 处理统计数据逻辑 return getRequest('背包库存API地址'); }) .then(bagData => { // 处理背包数据逻辑 }) .catch(e => console.error(e)); }
方案优势
- 完全保留通用请求函数的复用性,header设置、JSON解析、错误捕获等通用逻辑全部封装在
getRequest内,无需重复编写 - 原生支持等待请求完成的需求,无需自行实现变量监听逻辑
- 顺序请求的逻辑清晰易维护,匹配你需要按顺序发起多个API请求的场景
- 错误处理统一,不需要每个请求单独写状态判断逻辑
内容的提问来源于stack exchange,提问作者knighToFdemonS
相关产品推荐
相关产品推荐

