Promise 本身不支持轮询,但可通过 setTimeout/setInterval 结合 Promise 链、递归调用或 async/await 实现可控轮询,支持超时、重试、取消及条件终止。

Promise 本身不直接支持轮询,但可以结合 setTimeout 或 setInterval + Promise 链式调用,实现可控、可取消、带超时和重试逻辑的轮询任务。
用 Promise 封装单次请求
轮询的基础是能反复执行一个返回 Promise 的请求函数。先确保请求本身是 Promise 化的(比如用 fetch):
function pollTask() {
return fetch('/api/task-status')
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
});
}用递归 Promise 实现带条件终止的轮询
推荐用递归方式控制流程,避免 setInterval 难以清理、状态不同步的问题。每次成功后判断是否继续:
- 检查响应中是否有完成标识(如
status === 'success'或done: true) - 满足条件则 resolve 结果;否则延迟后再次调用自身
- 加入最大重试次数或超时时间,防止无限循环
function startPolling({ maxRetries = 10, interval = 1000, timeout = 30000 }) {
const startTime = Date.now();
<p>function attempt(retryCount = 0) {
// 超时检查
if (Date.now() - startTime > timeout) {
return Promise.reject(new Error('Polling timeout'));
}
// 重试上限检查
if (retryCount >= maxRetries) {
return Promise.reject(new Error('Max retries exceeded'));
}</p><pre class="brush:php;toolbar:false;">return pollTask()
.then(data => {
if (data.status === 'completed' || data.done) {
return data; // ✅ 成功终止
}
return new Promise(resolve =>
setTimeout(() => resolve(attempt(retryCount + 1)), interval)
);
});}
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
return attempt(); }
支持手动取消的轮询(推荐用于实际项目)
真实场景中常需中途停止轮询(如用户离开页面、任务被取消)。可用 AbortController 配合 Promise.race:
- 每个请求携带 signal,便于中断网络请求
- 用
Promise.race在「请求完成」和「取消信号」之间择一响应 - 外部保留 controller 实例,调用
abort()即可停止
function createCancelablePoller({ interval = 1000, timeout = 30000 }) {
let controller = new AbortController();
<p>function poll() {
return Promise.race([
pollTask().catch(err => {
if (err.name === 'AbortError') throw new Error('Polling canceled');
throw err;
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Polling timeout')), timeout)
)
]).then(data => {
if (data.status === 'completed') return data;
return new Promise(resolve =>
setTimeout(() => resolve(poll()), interval)
);
});
}</p><p>return {
start: () => poll(),
cancel: () => controller.abort()
};
}</p><p>// 使用示例
const poller = createCancelablePoller({ interval: 2000 });
poller.start()
.then(result => console.log('Done:', result))
.catch(err => console.error('Stopped:', err));</p><p>// 后续可随时调用
// poller.cancel();配合 async/await 写法更直观
如果不用链式调用,async/await + while 循环写法更易读(注意仍需防死循环):
async function pollWithAwait(options = {}) {
const { maxRetries = 10, interval = 1000, timeout = 30000 } = options;
const startTime = Date.now();
<p>for (let i = 0; i < maxRetries; i++) {
if (Date.now() - startTime > timeout) {
throw new Error('Timeout');
}</p><pre class="brush:php;toolbar:false;">try {
const data = await pollTask();
if (data.status === 'completed') return data;
} catch (err) {
console.warn('Poll failed, retrying...', err);
}
await new Promise(r => setTimeout(r, interval));}
立即学习“Java免费学习笔记(深入)”;
throw new Error('Max retries reached'); }

















