[英]How to force repaint in JS?
What I am trying to achieve: 我想要达到的目标:
Here's the stripped code: 这是剥离的代码:
<div id ="di" onclick="calc()">initial</div>
<script>
function calc()
{
var n,a=0;
document.getElementById('di').textContent="calculation in progress";
for(n=0;n<1000000000;n++) // Here's the time consuming calculation
{
a=a+n; // for clarity's sake, I removed a complicated math formula here
}
document.getElementById('di').textContent="done "+a;
}
</script>
When I run it and click on the div, it takes a while and then changes the text to "done", so the user does not see the "calculation in progress" message at all - this is my problem. 当我运行它并单击div时,它需要一段时间,然后将文本更改为“完成”,因此用户根本看不到“计算进行中”消息-这是我的问题。
To force a screen repaint to display the message before the calculations start, other threads suggest modifying CSS, hiding and immediately unhiding the element or using setTimeout, but nothing worked. 为了强制屏幕重新绘制以在计算开始之前显示消息,其他线程建议修改CSS,隐藏并立即取消隐藏元素或使用setTimeout,但是没有任何效果。
This will be a program that draws complicated math objects (fractals) and I will use canvas instead of a div, but I simplified the example above. 这将是一个绘制复杂数学对象(分形)的程序,我将使用canvas而不是div,但是我简化了上面的示例。 Because of the future graphic interface, using "alert()" is not an option - the "calculation in progress" screen should turn to "done" immediately upon completion of the calculations.
由于将来会有图形界面,因此不能选择使用“ alert()”-计算完成后,“计算进行中”屏幕应立即变为“完成”。
IMO an easy way to handle this is to have your computation performed in "small" chunks by a timer function, for example: IMO处理此问题的简单方法是通过计时器函数以“较小”的块执行计算,例如:
function calcFractal(x0, y0, x1, y1) {
... compute the fractal for the tile (x0, y0)-(x1, y1) ...
}
var x = 0, y = 0;
function nextTile() {
calcFractal(x, y, x+tw, y+th);
x += tw;
if (x >= width) {
x = 0;
y += th;
}
if (y < height) setTimeout(nextTile, 0);
}
nextTile();
This allows you to show progress (including for example a low resolution of the fractal, the percentage of the computation) and to allow interruption (with onclick
events on a stop button for example). 这使您可以显示进度(例如,包括分形的低分辨率,计算的百分比)并允许中断(例如,带有停止按钮的
onclick
事件)。
If the tiles are not tiny the overhead will be acceptable, still maintaining the page reasonably responsive to both repaints and user interaction. 如果磁贴不是很小,那么开销是可以接受的,仍然可以合理地响应重新绘制和用户交互来保持页面。
You need to either wait a millisecond or do the calculations with a Worker. 您需要等待一毫秒或与Worker进行计算。
The first example is probably the easiest, instead of calling calc
directly, create a new function 第一个示例可能是最简单的,而不是直接调用
calc
,而是创建一个新函数
function caller() {
// insert "calculation in progress" in the body
setTimeout(calc, 1);
}
Then call caller
. 然后呼叫
caller
。
Because modern browsers may delay redrawing for better frame rate, versions with setTimeout
may not work with too low time-outs. 由于现代浏览器可能会延迟重新绘制以获得更好的帧速率,因此带有
setTimeout
版本可能无法在太低的超时时间内工作。
If possible you need to use requestAnimationFrame . 如果可能,您需要使用requestAnimationFrame 。 If its not posible then @Bálint answer should work, but with much bigger timeout (in my tests in Firefox its began work with timeout near 20-30).
如果它不可能,那么@Bálint答案应该可以工作,但是超时时间要大得多(在Firefox中我的测试中,它的工作时间是20-30附近)。 Actual timeout value is browser dependent (and probably system dependent too)
实际超时值取决于浏览器(可能也取决于系统)
function very_long_func(){
el= document.getElementById('di');
requestAnimationFrame( function(){
//edit dom for new frame;
el.textContent = 'calculation in progress'
//browser will wait for this functions end, before start redraw.
//So actual calucation must run outside of it
setTimeout( function_with_actual_calculation, 1 );
})
}
function function_with_actual_calculation(){
//..your math here + updating textContent to "done" in the end.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.