如何提前执行HTTP请求并在鼠标交互时处理结果?能否无延迟判断请求完成?
如何判断预加载的HTTP请求是否完成后再执行打开链接操作
需求回顾
提前发起HTTP请求获取目标链接,当鼠标移动到页面指定元素上时,仅在请求完成后打开返回的最终链接,避免使用固定延迟(如1500ms)等待请求。
原代码的问题
原代码通过全局变量jhref存储链接,但没有明确标记请求的完成状态,鼠标hover时无法确定jhref是否已经是请求后的最终链接,容易出现打开初始链接(http://aaa.com)的情况。
解决方案1:用状态变量跟踪请求状态
新增一个状态变量标记请求的进展,鼠标hover时先判断状态,再执行对应操作:
// 全局变量:存储最终链接和请求状态 let jhref = 'http://aaa.com'; let requestStatus = 'pending'; // 可选值: pending(进行中)/success(成功)/error(失败) function getWebsite(s) { GM_xmlhttpRequest({ method: 'GET', url: jhref, onload: function (result) { let domNew = new DOMParser().parseFromString(result.responseText, 'text/html'); let linkElement = domNew.querySelectorAll('.item>a')[0]; if (linkElement) { jhref = linkElement.href; requestStatus = 'success'; } else { requestStatus = 'error'; console.log('未找到目标链接'); } }, onerror: function (result) { requestStatus = 'error'; console.log('请求失败:', result); }, onabort: function() { requestStatus = 'error'; console.log('请求被中止'); } }); } // 立即发起预加载请求 getWebsite(text); // 给目标元素绑定鼠标移入事件(替换成你的元素选择器) document.querySelector('.target-element').addEventListener('mouseover', function() { switch(requestStatus) { case 'success': window.open(jhref); break; case 'pending': console.log('请求还在处理中,请稍候'); // 可选:如果想等请求完成再打开,可以加个轮询 // const checkStatus = setInterval(() => { // if(requestStatus === 'success') { // window.open(jhref); // clearInterval(checkStatus); // } // }, 100); break; case 'error': console.log('请求失败,无法打开链接'); break; } });
解决方案2:用Promise封装请求(更优雅)
将请求封装为Promise,利用Promise的状态自动跟踪请求进展,鼠标hover时直接等待请求完成:
// 把请求封装成Promise function getWebsite(s) { const initialUrl = 'http://aaa.com'; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: initialUrl, onload: function (result) { let domNew = new DOMParser().parseFromString(result.responseText, 'text/html'); let linkElement = domNew.querySelectorAll('.item>a')[0]; if (linkElement) { resolve(linkElement.href); // 请求成功,返回最终链接 } else { reject(new Error('未找到目标链接')); } }, onerror: function (result) { reject(new Error('请求失败: ' + result.statusText)); }, onabort: function() { reject(new Error('请求被中止')); } }); }); } // 立即发起预加载请求,得到Promise实例 const linkPromise = getWebsite(text); // 给目标元素绑定鼠标移入事件(替换成你的元素选择器) document.querySelector('.target-element').addEventListener('mouseover', async function() { try { // 等待请求完成(如果已经完成会直接返回结果) const finalLink = await linkPromise; window.open(finalLink); } catch (err) { console.log('无法打开链接:', err.message); } });
方案对比
- 方案1适合简单场景,状态变量直观易懂,适合快速改造原有代码
- 方案2符合现代JS异步编程习惯,处理异步逻辑更优雅,无需手动维护状态,还能自然等待请求完成
内容的提问来源于stack exchange,提问作者lyscop
相关产品推荐
相关产品推荐

