用async函数实现轮询任务的核心是递归调用+await控制串行执行,避免并发堆积;需包含退出条件、错误处理、取消机制及Promise封装以适配不同场景。

用 async 函数实现轮询任务,核心是让每次请求“等完再发下一次”,避免并发堆积或无节制重试。关键不是单纯用 setInterval,而是用递归调用 + await 控制节奏,并加入退出条件和错误处理。
基础递归轮询(带间隔与停止条件)
最常用也最可控的方式:写一个自调用的 async 函数,每次 fetch 后用 setTimeout 或 await new Promise(resolve => setTimeout(resolve, ms)) 延迟下一次执行。
- 用
await等待请求完成,再等间隔时间,确保串行 - 用布尔变量(如
shouldPoll)或响应内容判断是否继续 - 避免用
setInterval+ async,否则定时器不等 await,容易堆积请求
示例:
async function poll(url, interval = 1000, maxAttempts = 10) {
let attempts = 0;
async function run() {
if (attempts >= maxAttempts) {
console.log('轮询已超限,停止');
return;
}
attempts++;
try {
const res = await fetch(url);
const data = await res.json();
console.log('获取到:', data);
// 假设 data.status === 'done' 表示任务完成
if (data.status === 'done') {
console.log('轮询成功结束');
return;
}
} catch (err) {
console.error('请求失败:', err);
}
// 等待间隔后继续
await new Promise(resolve => setTimeout(resolve, interval));
run(); // 递归调用
}
run();
}支持取消的轮询(用 AbortController + 标志位)
实际项目中常需手动停止轮询(比如用户离开页面、表单提交成功)。仅靠闭包变量不够健壮,建议结合 AbortController 和显式取消函数。
- 创建控制器,在每次 fetch 中传入
signal - 暴露
cancel()方法,置标志位并中止 pending 请求 - 递归调用前检查是否已取消,避免“幽灵调用”
示例:
function createPoller(url, interval = 1000) {
let controller = null;
let stopped = false;
<p>const poll = async function run() {
if (stopped) return;</p><pre class="brush:php;toolbar:false;">controller = new AbortController();
try {
const res = await fetch(url, { signal: controller.signal });
const data = await res.json();
console.log('轮询数据:', data);
if (data.status === 'success' || data.finished) {
console.log('任务完成,自动停止');
stopped = true;
return;
}
} catch (err) {
if (err.name === 'AbortError') {
console.log('本次轮询已被取消');
return;
}
console.error('请求异常:', err);
}
await new Promise(resolve => setTimeout(resolve, interval));
if (!stopped) run();};
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
return { start: () => { if (stopped) { stopped = false; poll(); } }, cancel: () => { stopped = true; controller?.abort(); } }; }
// 使用 const poller = createPoller('/api/task-status', 2000); poller.start(); // 后续可随时调用 // poller.cancel();
封装成 Promise(适合等待结果的场景)
如果只是想“等某个接口返回成功再往下走”,可以把轮询包装成一个 Promise,resolve 成功结果,reject 超时或失败。
- 适合初始化页、弹窗确认后等待后台任务完成等同步流程
- 内部仍用递归 + await,但对外只暴露一个 Promise
- 可配置超时总时长(比只限制次数更直观)
示例:
async function waitForSuccess(url, options = {}) {
const {
interval = 1000,
timeout = 30000, // 总超时 30s
validate = data => data.status === 'done'
} = options;
<p>const startTime = Date.now();</p><p>async function attempt() {
if (Date.now() - startTime > timeout) {
throw new Error('轮询超时');
}</p><pre class="brush:php;toolbar:false;">try {
const res = await fetch(url);
const data = await res.json();
if (validate(data)) {
return data; // ✅ 成功,结束轮询
}
} catch (err) {
console.warn('轮询请求出错,继续...', err);
}
await new Promise(r => setTimeout(r, interval));
return attempt(); // 继续}
return attempt(); }
// 使用(像普通 Promise 一样 await) try { const result = await waitForSuccess('/api/deploy-status', { interval: 2000, timeout: 60000, validate: d => d.progress === 100 }); console.log('部署完成!', result); } catch (e) { console.error('等待失败:', e); }
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










