前端实现状态轮询与超时控制的定时器机制
在某些特殊业务场景下,后端无法直接返回完整数据,需通过前端主动轮询状态接口来判断数据准备就绪情况。本方案实现一个基于定时轮询的异步状态检测流程,支持3秒间隔轮询,30秒提示加载中,2分钟超时自动终止。
核心逻辑如下:页面初始化时启动状态检查,每3秒调用一次状态查询接口。当接口返回的 campaign 字段为 true 时,立即请求主列表数据并停止轮询;若持续超过120秒仍未就绪,则触发超时处理,显示超时提示并允许用户重试。
// 定义全局定时器标识
let pollingTimer = null;
// 状态检查与数据加载主方法
async checkAndLoad() {
// 清除旧定时器避免重复
if (pollingTimer) {
clearInterval(pollingTimer);
pollingTimer = null;
}
// 初始化状态
this.isLoading = true;
this.loadMessage = '';
this.isTimeout = false;
let startTime = Date.now();
const maxWaitTime = 120000; // 2分钟
// 启动轮询
pollingTimer = setInterval(async () => {
const elapsed = Date.now() - startTime;
// 超过30秒显示"拼命加载中"
if (elapsed >= 30000 && !this.loadMessage) {
this.loadMessage = '数据量较大,拼命加载中,请耐心等待';
}
// 每3秒执行一次状态查询
if (Math.floor(elapsed / 1000) % 3 === 0) {
try {
const result = await this.fetchStatus();
// 若状态已就绪,获取列表数据并退出轮询
if (result?.data?.campaign) {
await this.fetchPageData();
this.clearPolling();
return;
}
} catch (error) {
console.warn('状态查询失败:', error);
}
}
// 超时处理
if (elapsed >= maxWaitTime) {
this.clearPolling();
this.isTimeout = true;
this.tableData = [];
this.loadMessage = '数据量较大,加载超时,请稍后';
}
}, 1000);
// 组件销毁时清理定时器
this.$once('hook:beforeDestroy', () => {
this.clearPolling();
});
}
// 获取状态信息
async fetchStatus() {
const res = await this.$axios.post('/api/status/check', { /* params */ });
return res.data;
}
// 获取主列表数据
async fetchPageData() {
this.isLoading = true;
const res = await this.$axios.post('/api/data/page', { /* params */ });
if (res.data.status === 0) {
this.tableData = res.data.list || [];
this.totalCount = res.data.totalCount || 0;
this.$emit('updateTotal', { key: 'campaignNum', value: this.totalCount });
}
this.isLoading = false;
}
// 清除轮询并重置状态
clearPolling() {
if (pollingTimer) {
clearInterval(pollingTimer);
pollingTimer = null;
}
this.isLoading = false;
this.loadMessage = '';
}
在模板中通过条件渲染展示不同状态:
<template>
<el-table :data="tableData" v-loading="isLoading">
<el-table-column prop="name" label="名称" />
<!-- 其他列 -->
</el-table>
<div slot="empty">
<div v-if="isTimeout">
<span>数据量较大,加载超时,请稍后
<el-button @click="checkAndLoad" type="text">重试</el-button>
</span>
</div>
<span v-else>暂无数据</span>
</div>
</template>