
在web开发中,通过javascript与服务器进行数据交互是常见的需求。xmlhttprequest(xhr)是实现这一功能的核心api之一。然而,当xhr请求设置为同步模式(即req.open("head", url, false);中的第三个参数为false)时,它会阻塞浏览器的主线程,直到请求完成。这意味着在请求期间,用户界面将变得无响应,无法滚动、点击或执行任何其他操作,严重损害用户体验。现代浏览器普遍对此行为发出警告,并强烈建议避免在主线程中使用同步xhr。
原始的同步请求代码示例如下,它用于获取文件最后修改时间并计算其与当前时间的时间差:
<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>尽管这段代码能实现功能,但其同步特性会导致页面卡顿,尤其是在网络条件不佳或请求频率较高时。浏览器控制台通常会给出类似“Synchronous XMLHttpRequest on the main thread is deprecated...”的警告。
要解决同步XHR带来的问题,核心在于将其转换为异步模式。异步请求不会阻塞主线程,而是通过回调函数或事件监听器在请求完成后通知我们。
异步XHR通过以下两种方式处理响应:
以下是将原同步XHR代码转换为异步的实现,它利用addEventListener('load')来处理响应:
const pageload = new Date(); // 页面加载时间
const url = "Akut.txt"; // 目标文件URL
const whichHeader = "Last-Modified"; // 要获取的响应头
// 比较时间并更新UI的函数
const compareTimeToNow = (time) => {
let d = new Date();
let diffSec = Math.round((d - time) / 1000);
document.getElementById("time").textContent = Math.trunc(diffSec / 60) + " minutes"; // 显示自修改以来的分钟数
// 如果页面加载超过10秒且文件在5秒内被修改过,则刷新页面
if ((d - pageload) / 1000 > 10 && diffSec < 5) {
location.reload();
} else {
// 请求完成后,等待2.5秒再次发起请求,形成周期性检查
setTimeout(getHeader, 2500);
}
};
// XHR请求完成时的监听器
function reqListener() {
// console.log(this.responseText); // HEAD请求通常responseText为空
// 从响应头获取'Last-Modified'时间,并转换为Date对象,然后传递给compareTimeToNow
compareTimeToNow(new Date(this.getResponseHeader(whichHeader)).getTime());
}
// 发起HEAD请求的函数
const getHeader = () => {
const req = new XMLHttpRequest();
req.addEventListener("load", reqListener); // 监听load事件
req.open("HEAD", url); // 异步请求,默认第三个参数为true
req.send();
};
// 首次调用以启动周期性检查
getHeader();代码解析:
Fetch API是现代Web开发中进行网络请求的推荐方式,它基于Promise,提供了一种更强大、更灵活、更简洁的API来替代XMLHttpRequest。Fetch API的使用可以进一步简化代码,并提供更好的错误处理机制。
以下是使用Fetch API实现相同功能的代码:
const pageload = new Date(); // 页面加载时间
const url = "Akut.txt"; // 目标文件URL
const whichHeader = "Last-Modified"; // 要获取的响应头
// 比较时间并更新UI的函数(与XHR版本相同)
const compareTimeToNow = (time) => {
let d = new Date();
let diffSec = Math.round((d - time) / 1000);
document.getElementById("time").textContent = Math.trunc(diffSec / 60) + " minutes"; // 显示自修改以来的分钟数
if ((d - pageload) / 1000 > 10 && diffSec < 5) {
location.reload();
} else {
setTimeout(getHeader, 2500); // 周期性调度下一次请求
}
};
// 发起Fetch请求的函数
const getHeader = () => {
fetch(url, { method: 'HEAD' }) // 发起HEAD请求
.then(rsp => {
// 获取响应头,并转换为时间戳传递给compareTimeToNow
compareTimeToNow(new Date(rsp.headers.get(whichHeader)).getTime());
})
.catch(error => {
console.error("Fetch请求失败:", error);
// 失败后也应考虑是否继续调度下一次请求,例如延迟重试
setTimeout(getHeader, 5000); // 失败后延迟更久重试
});
};
// 首次调用以启动周期性检查
getHeader();代码解析:
将同步XMLHttpRequest请求转换为异步模式是优化Web性能的关键一步,它能有效避免主线程阻塞,提升用户体验。通过XMLHttpRequest的事件监听器或更现代、更强大的Fetch API,我们可以轻松实现非阻塞的网络请求。在选择具体实现方式时,应根据项目需求、浏览器兼容性以及对代码简洁性的偏好进行权衡。同时,对于周期性任务,采用setTimeout递归调用而非setInterval,并结合适当的错误处理,是构建健壮Web应用的最佳实践。
以上就是优化Web性能:使用异步XHR与Fetch API获取文件修改时间的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号