同步AJAX调用时JS更新与CSS动画在Chrome/Edge不生效问题咨询
问题诱因
- 核心原因是使用了阻塞式同步XMLHttpRequest:Chrome、Edge采用的Blink渲染引擎中,主线程发起的同步网络请求会完全阻塞页面的重绘、DOM更新、CSS动画执行流程,所有请求过程中对DOM的修改都会被缓存,直到所有同步请求全部执行完成后才会一次性批量渲染,因此会出现进度条不动、文档计数始终为0,最后直接跳转到100%的表现。Firefox的渲染调度策略和Blink内核存在差异,所以代码在Firefox上可以正常运行,这属于浏览器实现差异,代码本身不符合前端开发最佳实践。
- 代码存在逻辑错误:
showSlowly方法的for循环中window.onload = execDocsWebscript(element)属于错误写法,这里会直接执行execDocsWebscript函数,再将函数返回值(通常为undefined)赋值给window.onload,既没有实现等待页面加载完成再执行请求的效果,还会在循环时直接触发所有同步请求。
修复方案
1. 将同步XMLHttpRequest改为异步串行请求
修改请求逻辑,放弃同步模式,采用异步请求+回调链式调用的方式按顺序处理每个用户的请求,调整后参考代码如下:
// 全局变量,记录当前处理的用户下标、总文档数、用户列表 let currentUserIndex = 0; let totalDocLength = 0; let userArray = []; function execDocsWebscript() { // 所有用户处理完成,更新最终进度 if (currentUserIndex >= userArray.length) { doProgress(userArray.length); return; } const user = userArray[currentUserIndex]; init_XMLHttpRequest(); // doRequest保持异步模式,请求完成后调用appendRespData回调 doRequest("url"+user, 'GET', appendRespData); // 更新当前进度 doProgress(currentUserIndex + 1); currentUserIndex++; } function appendRespData() { if (peticionHTTP.readyState == 4 && peticionHTTP.status == 200) { const docLength = AJAXParser(peticionHTTP); totalDocLength += +docLength; document.getElementById('tbody').insertAdjacentHTML('beforeend',peticionHTTP.responseText); document.getElementById('loadingDocuCount').innerHTML = "Documents found: "+totalDocLength; // 当前用户请求处理完成,调用下一个用户的请求 execDocsWebscript(); } } function doProgress(i) { const currentProgress = (i/userArray.length)*100; const progBar = document.getElementById('progBar'); progBar.setAttribute('aria-valuenow',currentProgress); // 直接修改style属性比setAttribute兼容性更好 progBar.style.width = currentProgress + '%'; progBar.innerHTML = Math.round(currentProgress)+'%'; if(currentProgress == 100) { document.getElementById('progText').innerHTML = "DONE!"; } } // 页面加载完成后初始化用户列表,开始执行请求 window.onload = function() { // 此处先执行获取用户列表的逻辑,赋值给userArray execDocsWebscript(); }
2. 优化CSS动画稳定性
现有CSS动画逻辑本身没有问题,之前无法运行是因为主线程被同步请求阻塞,修改为异步请求后即可自动恢复正常。如果仍有偶发卡顿,可以给动画元素添加GPU加速属性,让动画交给合成线程处理,不受主线程任务阻塞影响:
.jumping-dots span { position: relative; bottom: 0px; animation: jump 2s infinite; -webkit-animation: jump 2s infinite; /* 新增以下属性触发GPU加速 */ transform: translate3d(0, 0, 0); }
内容的提问来源于stack exchange,提问作者Fabio Barcelona
相关产品推荐
相关产品推荐

