显式等待与 Timeout 的协同策略
显式等待通过动态检测 DOM 状态触发操作,避免静态等待的时间浪费。Timeout 机制作为兜底方案,防止无限等待导致的线程阻塞。两者结合可显著提升复杂 Ajax 页面的稳定性。
显式等待实现逻辑
const waitForElement = (selector, timeout = 30000) => {
const startTime = Date.now();
return new Promise((resolve, reject) => {
const checkInterval = setInterval(() => {
const element = document.querySelector(selector);
if (element) {
clearInterval(checkInterval);
resolve(element);
} else if (Date.now() - startTime > timeout) {
clearInterval(checkInterval);
reject(new Error(`Element ${selector} not found within ${timeout}ms`));
}
}, 100);
});
};
动态条件检测机制
采用多维度检测策略应对不同 Ajax 场景:
- 元素存在性检测:
document.querySelector('#result') - 元素内容检测:
element.textContent.includes('su***ess') - 样式属性检测:
get***putedStyle(element).display !== 'none' - 网络活动检测:
window.performance.getEntriesByType('resource')
const waitForCondition = (conditionFn, timeout = 30000) => {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const check = () => {
try {
if (conditionFn()) {
resolve();
} else if (Date.now() - startTime > timeout) {
reject(new Error('Condition not met within timeout'));
} else {
requestAnimationFrame(check);
}
} catch (error) {
reject(error);
}
};
check();
});
};
分层超时配置方案
根据交互类型设置差异化超时阈值:
- 常规 DOM 操作:5-10 秒
- 中等复杂度 Ajax:15-20 秒
- 文件上传/下载:30-60 秒
- 长轮询请求:120 秒以上
const TIMEOUT_PROFILES = {
critical: 5000,
standard: 15000,
heavy: 30000,
extended: 60000
};
function fetchWithTimeout(url, { timeout = TIMEOUT_PROFILES.standard } = {}) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
return fetch(url, { signal: controller.signal })
.finally(() => clearTimeout(timeoutId));
}
异常处理与重试机制
实现指数退避算法应对瞬时故障:
async function retryWithBackoff(operation, maxRetries = 3, baseDelay = 1000) {
let attempt = 0;
while (attempt < maxRetries) {
try {
return await operation();
} catch (error) {
attempt++;
if (attempt >= maxRetries) throw error;
const delay = baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
性能监控与阈值优化
通过 Performance Observer 动态调整等待策略:
const perfObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach(entry => {
console.log(`[${entry.name}] Duration: ${entry.duration.toFixed(2)}ms`);
if (entry.duration > 2000) {
console.warn('Long-running operation detected');
}
});
});
perfObserver.observe({
entryTypes: ['resource', 'paint', 'measure']
});
最佳实践组合方案
- 对关键交互路径使用短超时(5-10秒)与快速重试(2-3次)
- 数据加载场景采用中等超时(15-30秒)配合进度反馈
- 文件处理等耗时操作实施长超时(60秒+)与后台轮询
- 所有等待操作必须包含用户可感知的加载状态提示