jQuery/Javascript - 如何在继续执行函数之前等待操作的 DOM 更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7342084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jQuery/Javascript - How to wait for manipulated DOM to update before proceeding with function
提问by pcormier
What I'm trying to do is to update a simple div to say "Processing..." before executing a CPU-intensive script (it takes 3-12 seconds to run, no AJAX) then update the div to say "Finished!" when done.
我想要做的是在执行 CPU 密集型脚本(运行需要 3-12 秒,没有 AJAX)之前更新一个简单的 div 说“处理...”然后更新 div 说“完成! ” 完成后。
What I'm seeing is the div never gets updated with "Processing...". If I set a breakpoint immediately after that command, then the div text does get updated, so I know the syntax is correct. Same behavior in IE9, FF6, Chrome13.
我所看到的是 div 永远不会更新为“正在处理...”。如果我在该命令之后立即设置断点,则 div 文本会更新,所以我知道语法是正确的。在 IE9、FF6、Chrome13 中的行为相同。
Even when bypassing jQuery and using basic raw Javascript, I see the same issue.
即使绕过 jQuery 并使用基本的原始 Javascript,我也看到了同样的问题。
You'd think this would have an easy answer. However, since the jQuery .html() and .text() don't have a callback hook, that's not an option. It's also not animated, so there is no .queue to manipulate.
你会认为这会有一个简单的答案。然而,由于 jQuery .html() 和 .text() 没有回调钩子,这不是一个选项。它也不是动画的,所以没有 .queue 可以操作。
You can test this yourselves using the sample code I prepared below that shows both the jQuery and Javascript implementations with a 5 second high-CPU function. The code is easy to follow. When you click either the button or the link, you never see "Processing..."
您可以使用我在下面准备的示例代码自行测试,该示例代码显示了具有 5 秒高 CPU 功能的 jQuery 和 Javascript 实现。代码很容易理解。当您单击按钮或链接时,您永远不会看到“正在处理...”
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script type="text/javascript">
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
document.getElementById('msg').innerHTML = 'Processing JS...';
start = new Date();
end = addSecs(start,5);
do {start = new Date();} while (end-start > 0);
document.getElementById('msg').innerHTML = 'Finished JS';
}
$(function() {
$('button').click(function(){
$('div').text('Processing JQ...');
start = new Date();
end = addSecs(start,5);
do {start = new Date();} while (end-start > 0);
$('div').text('Finished JQ');
});
});
</script>
</head>
<body>
<div id="msg">Not Started</div>
<button>jQuery</button>
<a href="#" onclick="doRun()">javascript</a>
</body>
</html>
采纳答案by Kevin B
set it to processing, then do a setTimeout to prevent the cpu intensive task from running until after the div has been updated.
将其设置为处理,然后执行 setTimeout 以防止 cpu 密集型任务运行,直到 div 更新后。
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script>
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
document.getElementById('msg').innerHTML = 'Processing JS...';
setTimeout(function(){
start = new Date();
end = addSecs(start,5);
do {start = new Date();} while (end-start > 0);
document.getElementById('msg').innerHTML = 'Finished Processing';
},10);
}
$(function() {
$('button').click(doRun);
});
</script>
</head>
<body>
<div id="msg">Not Started</div>
<button>jQuery</button>
<a href="#" onclick="doRun()">javascript</a>
</body>
</html>
you can modify the setTimeout delay as needed, it may need to be larger for slower machines/browsers.
您可以根据需要修改 setTimeout 延迟,对于较慢的机器/浏览器,它可能需要更大。
Edit:
编辑:
You could also use an alert or a confirm dialog to allow the page time to update.
您还可以使用警报或确认对话框来允许页面时间更新。
document.getElementById('msg').innerHTML = 'Processing JS...';
if ( confirm( "This task may take several seconds. Do you wish to continue?" ) ) {
// run code here
}
回答by Paul
You have a loop that runs for 5 seconds and freezes the web browser during that time. Since the web browser is frozen it can't do any rendering. You should be using setTimeout()
instead of a loop, but I'm assuming that loop is just a replacement for a CPU intensive function that takes a while? You can use setTimeout to give the browser a chance to render before executing your function:
您有一个循环运行 5 秒钟并在此期间冻结 Web 浏览器。由于 Web 浏览器已冻结,因此无法进行任何渲染。您应该使用setTimeout()
而不是循环,但我假设循环只是替代需要一段时间的 CPU 密集型功能?您可以使用 setTimeout 在执行您的函数之前让浏览器有机会进行渲染:
jQuery:
jQuery:
$(function() {
$('button').click(function(){
(function(cont){
$('div').text('Processing JQ...');
start = new Date();
end = addSecs(start,5);
setTimeout(cont, 1);
})(function(){
do {start = new Date();} while (end-start > 0);
$('div').text('Finished JQ');
})
});
});
Vanilla JS:
香草JS:
document.getElementsByTagName('a')[0].onclick = function(){
doRun(function(){
do {start = new Date();} while (end-start > 0);
document.getElementById('msg').innerHTML = 'Finished JS';
});
return false;
};
function doRun(cont){
document.getElementById('msg').innerHTML = 'Processing JS...';
start = new Date();
end = addSecs(start,5);
setTimeout(cont, 1);
}
You should also remember to always declare all variables using the var keyword, and avoid exposing them to the global scope. Here is a JSFiddle:
您还应该记住始终使用 var 关键字声明所有变量,并避免将它们暴露给全局范围。这是一个 JSFiddle:
回答by BananaAcid
I had to wait for jQuery to manipulate the DOMand then grap the changes (load form fields multiple times into a form, then to submit it). The DOM grew and the insertion took longer and longer. I saved the changes using ajax to have to user to be able to continue where he left off.
我不得不等待 jQuery 操作 DOM,然后抓取更改(将表单字段多次加载到表单中,然后提交)。DOM 增长,插入花费的时间越来越长。我使用 ajax 保存了更改,以便用户能够从他离开的地方继续。
This did NOT WORKas intended:
这没有按预期工作:
jQuery('.parentEl').prepend('<p>newContent</p>');
doSave(); // wrapping it into timeout was to short as well sometimes
Since jQuery functions like .prepend()
do continue the chain only when done, the following seemed to do the trick:
由于jQuery的功能,喜欢.prepend()
做继续做连锁,只有当,下面似乎这样的伎俩:
jQuery('.parentEl').prepend('<p>newContent</p>').queue(function() {
doSave();
});
回答by Estradiaz
As of 2019 one uses doublerequesAnimationFrame
to skip a frame instead of creating a race condition using setTimeout.
截至 2019 年,使用doublerequesAnimationFrame
跳过一帧,而不是使用 setTimeout 创建竞争条件。
....
function doRun() {
document.getElementById('msg').innerHTML = 'Processing JS...';
requestAnimationFrame(() =>
requestAnimationFrame(function(){
start = new Date();
end = addSecs(start,5);
do {start = new Date();} while (end-start > 0);
document.getElementById('msg').innerHTML = 'Finished Processing';
}))
}
...