问题描述
我有一个普通的 Javascript,可以将 img 的 src 属性设置为 data-uri。
在分配给 onload
事件的函数中,我尝试在页面上显示一些可能需要一段时间的准备工作的进度(生成了多个画布元素并设置了一些设置)。
这是应该呈现进度条的函数:
let progress = document.querySelector('.progress');
function showProgress(message,percent) {
console.log(message + ' (' + (percent * 100).toFixed(0) + '%)');
progress.querySelector('.progress--message').innerHTML = message;
progress.querySelector('.progress--bar-container--bar').style.width = (percent * 100).toFixed(0) + '%';
}
代码是这样运行的:
img.onload = function() {
showProgress('Preparing image...' .1);
// Some preparations...
showProgress('Preparing tools...',.2);
// etc...
showProgress('Done...',1);
}
控制台日志按预期工作,但 DOM 元素的渲染会停止,直到函数结束,并在一切准备就绪后显示“完成”状态。
在 onload
事件处理中是否存在任何渲染阻塞,是否可以绕过?或者我错过了什么?代码本身对结果没有任何影响。甚至函数中的第一行也有这种奇怪的行为。
解决方法
除非您使用后台 Web Workers 按摩(更复杂,尤其是在您的情况下),渲染进度条只能在从您的服务器完全返回后发生。脚本;因此,在每次 showProgress
调用之后。现在,如何返回,渲染然后重新启动剩余的?嗯,这就是 0 毫秒的 setTimeout
派上用场的地方。有了它,以下应该可以工作:
img.onload = function() {
showProgress('Preparing image...' .1);
setTimeout(function() {
// Some preparations...
showProgress('Preparing tools...',.2);
setTimeout(function() {
// etc...
showProgress('Done...',1);
},0);
},0);
}
嵌套代码的另一种方法是一种递归调用 - 但每次调用都会在以下开始之前完成 - 在一系列步骤上,如下所示:
steps = [
function() { // first step (img loading just completed so,show Preparing it right away)
showProgress('Preparing image...',.1);
},function() { // second step
// Some preparations...
showProgress('Preparing tools...',.2);
},// other steps...
function() { // last step
// Last things to do...
showProgress('Done...',1);
}
];
// function that processes "steps" - array of at least 1 function - until empty
function displayAfterEachStep() {
steps.shift()(); // Pull out the first step and run it
if(steps.length > 0) // if there's still steps
setTimeout(displayAfterEachStep,0); // Recall the process after page rendering
}
img.onload = displayAfterEachStep;