简体   繁体   English

如何在JS中强制重绘?

[英]How to force repaint in JS?

What I am trying to achieve: 我想要达到的目标:

  1. user clicks on an element 用户点击一个元素
  2. the screen shows the "calculation in progress" screen 屏幕显示“计算进行中”屏幕
  3. the system performs time-consuming math calculations 系统执行耗时的数学计算
  4. the screen shows the result ("done") 屏幕显示结果(“完成”)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM