0

There are times when my widget needs to process millions of data in mouse leave event. This may take seconds depending upon the records to process. So I have decided to show a waiting popup before processing.

The problem is waiting popup (div overlay) is not visible at all. If I do the processing in a setTimeout with 10+ milliseconds delay, the overlay is visible and works as expected.

Overlay div

<div style="background: black; opacity: 0.6; position: absolute; z-index: 1000; pointer-events: none; width: 810px; height: 450px; left: 8px; top: 29px; display: none;"></div>

In mouse leave event,

overlay.style.display = "block";
widget.processRecords(data); //this function may take seconds depending upon data
overlay.style.display = "none";

I know that absolute positioning should trigger minimal reflow. But it is not working. I thought maybe there is something wrong with my div element. But running the above code with a delay of 10 milliseconds, I can see the overlay till the widget completes processing

Overlay with delay

overlay.style.display = "block";
window.setTimeout(function(){
    this.processRecords(data); //this function may take seconds depending upon data
    overlay.style.display = "none";
}, 10);

Adding a delay works, but 10 milliseconds of processing gets wasted. Is there any other way to force the browser to reflow an absolutely positioned element. I saw other stack overflow questions about forcing reflows but none of them has a solid answer. I also referred the following link to force reflow of an element https://gist.github.com/paulirish/5d52fb081b3570c81e3a but none of them has any effect other than delay.

Browser: Chrome, Version: 53

Edit: I asked this question to understand more about reflows in browser and how to control them. There are many drawbacks in solution to the other question.

1) Data processing should wait for 10 milli-seconds unnecessarily

2) If it is a simple function, I can use it inside a setTimeout or setInterval easily. But I'm working on a widget which deals with KB's of code. It requires a lot of change addition to the delay.

3)If I need to change the style of 20 div elements, then 200 milliseconds will be wasted

4)The solution in other question uses a timeout inside a timeout and so on for processing.

I'm just saying that the answer in other question is not suitable in this scenario. There should be some other way or method to trigger the reflow of browser using JavaScript and I'm looking for that.

Kira
  • 1,403
  • 1
  • 17
  • 46
  • Then put the timeout to one (or zero) if you're worried about 10ms. Probably not worth optimizing for 10ms in 1 function. But yeah, you'll have to 'stop' doing js for a ms so the browser can reflow. Is there any reason why you chose 10ms as the delay? Btw, we are assuming here that processRecords is fully synchronous right? If it is async, the problem is that the display gets set back to none too fast, and you just need a callback. – Shilly Feb 01 '17 at 10:58
  • I tried upto 5 ms, but overlay is not visible during that time. – Kira Feb 01 '17 at 11:07
  • This is just my thinking. I don't have any proof. I think browser waits for some fixed time. If a new request for reflow comes within the fixed time, it again waits for the fixed time and so on. This makes the overlay to wait until processing gets completed – Kira Feb 01 '17 at 11:09
  • It will wait with all reflows until all js has stopped calculating, hence using timeout works, sicne this always places the timedout js at the back of the queue, after any reflows that have to happen. So setting the timeout to 0 or to 1000 or anything in between shouldn't make a difference visually. Can you confirm that processRecords will not like, do an ajax call or other async action that makes `overlay.style.display = "none";` run before the actual reflow happens? – Shilly Feb 01 '17 at 11:13
  • yes, it will not do any ajax or async or overlay.style.display = "none". – Kira Feb 01 '17 at 11:29
  • Possible duplicate of [DOM style change waiting for pause](http://stackoverflow.com/questions/4124674/dom-style-change-waiting-for-pause) – CBroe Feb 01 '17 at 12:06
  • You need to introduce some sort of “break” into your JS, otherwise it will run the whole thing and only hand control back over to the rendering engine after it is finished. Using a timeout is one way to achieve this, requestAnimationFrame would be another. And there is also a couple of properties that can cause a repaint simply when they are _read_, such as offsetHeight. – CBroe Feb 01 '17 at 12:08
  • @CBroe, I am looking for a way to trigger the reflow of browser instead of delaying the JS. Also, note that my div element is absolutely positioned. I heard browsers are quick in this scenario – Kira Feb 01 '17 at 13:22
  • Absolute positioning has nothing to do with this. Again: If you have script code that runs “in one go” without any interruptions, then control will only be handed back to the rendering engine after that whole block has executed. – CBroe Feb 01 '17 at 13:29
  • @CBroe, I cannot believe what you are saying. If this is a limitation to the browser, then it will be documented somewhere. I can hardly find any document related to this – Kira Feb 01 '17 at 13:55
  • You should be able to find enough places (here on SO and elsewhere), where people explain the same thing I just did, such as f.e. http://stackoverflow.com/a/17000032/1427878 – CBroe Feb 01 '17 at 14:36

0 Answers0