如何将获取文件Last-Modified的同步XMLHttpRequest改为异步?
异步改造XMLHttpRequest实现文件修改检测
问题背景
原同步代码可获取服务器文件Last-Modified时间,实现文件修改检测、自动刷新页面和显示修改后时长,但存在两个问题:
- 浏览器抛出「主线程同步XMLHttpRequest已废弃」警告
- 多窗口运行时会导致电脑卡顿
尝试改为异步版本后无法正确获取Last-Modified时间,返回NaN,需要完成异步改造。
原同步代码
<script> var pageload = new Date(); function fetchHeader(url, wch) { try { var req=new XMLHttpRequest(); req.open("HEAD", url, false); req.send(null); if(req.status== 200){ return req.getResponseHeader(wch); } else return false; } catch(er) { return er.message; } } window.setInterval(function(){ var time = Date.parse(fetchHeader("Akut.txt",'Last-Modified')); var d = new Date(); var diffSec = Math.round((d - time) / 1000); document.getElementById("time").innerHTML = Math.trunc(diffSec/60) + " minutes"; // time since it was modified if ((d-pageload)/1000 > 10 && diffSec < 5 ){ location.reload(); } }, 2500); </script>
失败的异步尝试
<script> function fetchHeader(url, wch) { try { var xhr = new XMLHttpRequest() xhr.onreadystatechange = function() { if (this.readyState === this.DONE) { console.log(this.getResponseHeader(wch)); // assumed this would work but it doesn't } } xhr.open("HEAD", url) xhr.send() } catch(er) { return er.message; } } </script>
正确的异步改造方案
异步操作的核心是不能直接通过return返回结果,需要用Promise封装异步请求,再通过async/await处理异步流程:
1. 封装异步获取请求头的函数
function fetchHeader(url, wch) { return new Promise((resolve, reject) => { try { const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState === this.DONE) { if (this.status === 200) { resolve(this.getResponseHeader(wch)); } else { resolve(false); } } }; // 处理请求错误 xhr.onerror = () => reject(new Error('请求文件信息失败')); xhr.open("HEAD", url); xhr.send(); } catch (err) { reject(err.message); } }); }
2. 改造定时器逻辑
使用async/await等待异步请求结果,再执行后续的时间计算和页面刷新逻辑:
const pageload = new Date(); window.setInterval(async function() { try { const lastModifiedStr = await fetchHeader("Akut.txt", 'Last-Modified'); // 处理请求失败或状态非200的情况 if (!lastModifiedStr) return; const time = Date.parse(lastModifiedStr); // 处理时间解析失败的情况 if (isNaN(time)) { console.error('解析Last-Modified时间失败'); return; } const d = new Date(); const diffSec = Math.round((d - time) / 1000); document.getElementById("time").innerHTML = Math.trunc(diffSec / 60) + " minutes"; // 判断是否需要刷新页面 if ((d - pageload) / 1000 > 10 && diffSec < 5) { location.reload(); } } catch (err) { console.error('获取文件信息出错:', err); } }, 2500);
改造说明
- 之前的异步代码失败原因:
fetchHeader没有返回值,异步请求的结果无法被定时器中的代码获取,导致Date.parse接收不到有效参数返回NaN - 用Promise封装异步请求后,通过
await可以在定时器中等待请求完成,确保拿到有效结果后再执行后续逻辑 - 增加了错误处理,避免单个请求失败导致整个逻辑崩溃
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

