
本文介绍如何正确实现一个返回 Promise 的递归函数,通过每 2 秒轮询检测指定 DOM 元素是否出现,并在元素就绪时触发 .then() 回调。关键在于确保每次递归调用都返回并链式传递 Promise,而非丢失引用。
本文介绍如何正确实现一个返回 promise 的递归函数,通过每 2 秒轮询检测指定 dom 元素是否出现,并在元素就绪时触发 `.then()` 回调。关键在于确保每次递归调用都返回并链式传递 promise,而非丢失引用。
原始代码的问题在于:当元素未找到时,setTimeout 内部调用了 checkElement(),但该调用的返回值(即 Promise)被完全忽略,外层函数没有 return 任何 Promise,导致 checkElement().then(...) 中的 .then() 永远无法被链接和执行。
正确的做法是——让每一次调用(包括递归分支)都明确返回一个 Promise,并通过 .then() 将后续状态传递下去。以下是优化后的实现:
function checkElement() {
console.log("Check Element...");
if (jQuery('#idOfElement').length > 0) {
// 元素已存在:立即返回已解决的 Promise
return Promise.resolve();
} else {
// 元素暂未出现:返回一个新 Promise,在 2 秒后递归检查,并将结果透传
return new Promise((resolve, reject) => {
setTimeout(() => {
// 递归调用并链式 resolve —— 确保深层 resolve 能抵达最外层 .then()
checkElement().then(resolve).catch(reject);
}, 2000);
});
}
}
// 使用示例
checkElement()
.then(() => console.log("✅ Element Found"))
.catch(err => console.error("❌ Timeout or error occurred:", err));
✅ 关键要点说明:
- ✅ 必须 return Promise:每个分支(包括 else 分支)都要 return 一个 Promise,否则调用链断裂;
- ✅ 递归需链式传递:checkElement().then(resolve) 确保内层 Promise 的成功状态能“冒泡”至最外层;
- ✅ 建议添加错误防护:实际项目中应加入最大重试次数或超时机制,避免无限循环。例如可扩展为 checkElement(maxRetries = 10, delay = 2000);
- ✅ 兼容性提示:若不使用 jQuery,可用原生 document.querySelector('#idOfElement') !== null 替代判断逻辑。
⚠️ 注意事项:
长时间轮询可能影响性能,建议仅用于必要场景(如动态加载内容、第三方脚本注入等);生产环境推荐结合 MutationObserver 做更高效的元素监听。但对简单、可控的等待逻辑,上述 Promise + 递归 + setTimeout 方案简洁可靠、语义清晰、易于测试与调试。










