如何使用Promise配合setTimeout实现等待DOM元素存在时返回true
问题解决方法
原代码问题分析
- setTimeout 回调声明了
resolve形参,覆盖了外层 Promise 实例的 resolve 方法,导致 Promise 永远无法被正常决议 - 定位到目标元素后仅执行了回调函数,没有调用 resolve 向外传递返回值
- 未找到元素时递归调用生成的新 Promise 没有和外层 Promise 关联,外层 Promise 始终处于 pending 状态
修正后的轮询实现方案
function waitForElement(className, callBack){ return new Promise(function(resolve) { // 移除setTimeout回调的resolve形参,避免覆盖外层的resolve方法 window.setTimeout(function(){ var element = document.querySelector(className); if(element) { callBack?.(className, element); console.log("Element exists"); // 直接resolve你需要的true值 resolve(true); } else { console.log("Wait..."); // 把递归生成的Promise结果透传给外层resolve resolve(waitForElement(className, callBack)); } },1000) }); }; // 调用方式1:通过.then获取返回的true waitForElement(".helping-hand-sliding-data h2", function(){ // 你的自定义回调逻辑 }).then(res => { // res即为返回的true值 console.log(res); }) // 调用方式2:放在async函数内用await获取返回的true async function main() { const result = await waitForElement(".helping-hand-sliding-data h2", function(){}); // result即为返回的true值 console.log(result); } main();
更高性能的替代方案(MutationObserver)
无需每秒轮询DOM,仅在DOM发生变化时触发检测,性能开销更低:
function waitForElement(selector) { return new Promise((resolve) => { // 先检测当前是否已经存在目标元素 if (document.querySelector(selector)) { return resolve(true); } // 初始化DOM变化监听器 const observer = new MutationObserver(() => { if (document.querySelector(selector)) { observer.disconnect(); resolve(true); } }); // 监听整个页面的节点新增、子树更新行为 observer.observe(document.body, { childList: true, subtree: true }); }); } // 调用方式和轮询方案一致,通过.then或者await即可拿到返回的true
内容的提问来源于stack exchange,提问作者Reena Verma
相关产品推荐
相关产品推荐

