Dom iterate causes half webview rendering

im using android to open local web file and then iterate over dom and apply some changes. But while his iteration of the web pause stops to display the page in some random part, look at the gif:

what i have already done

var elements = document.querySelectorAll("P"); for(var i = 0; i < elements.length;i++) { //just iterating at the gif im chaging //but i tried without changing, just iterating and the result still the same } 

and now, to avoid rendering problems with every change of dom, I created documentFragment and changed dom in it (or just repeated) and returned html to the main document

 var x = document.getElementById('contentRoot'); //getting the element root from the DOCUMENT (not the fragment) var frag = document.createDocumentFragment(); //creating fragment var contentRoot = document.createElement("DIV"); // creating a new contentRoot html element contentRoot.id = 'contentRoot'; contentRoot.innerHTML = x.innerHTML; frag.appendChild( contentRoot ); var elements = frag.querySelectorAll("P"); for(var i = 0; i < elements.length;i++) { //just iterating at the gif im chaging //but i tried without changing, just iterating and the result still the same } document.body.innerHTML = frag.getElementById('contentRoot').innerHTML; //returning the edited html from the fragment so the webview will render/reflow just once everything not for each change 

Is there a way to maintain normal rendering without "cutting"?

PS: im, using the function to iterate over window.onload, so it only starts after all the dom loads in the browser, why is it still being cut? and just visualize again at the end of the iteration?

enter image description here

+5
source share
2 answers

The problem with JavaScript is that while JavaScript is running, the entire page is locked and will not display anything. If you have a very long cycle, this explains your problem.

Most desktop browsers will scroll at the same time that the page is displayed (I'm sure that if you run this page in the desktop browser, it won’t even let you scroll).

However, most mobile devices, looking to look fast and smooth, will draw the scroll separately from the page itself. The problem is that if JavaScript is stuck in a very long loop, the user will be able to scroll, but the page will not be displayed in front, eventually ending up in this empty white area where nothing is displayed.

I’m sure that if you try to scale the page while the function is running, it will look very blurry, since rendering does not happen.

One way to fix this problem is to use timers or the requestAnimationFrame API.

requestAnimationFrame supported by almost all modern browsers. What he does is turn off the code until the next frame is rendered and is usually used to create smooth animations.

Using this API, I created the following code ...

 var elements = document.querySelectorAll("P"); var i = 0; var j = elements.length; function iterate(){ // this acts as the body of your for loop // do stuff with the current selected DOM element here... // select dom element with elements[i] i++; if(i < j){ requestAnimationFrame(iterate); } } iterate(); 

Now the code above starts iterating the for loop for each frame of the animation. Assuming your device is running at 60 frames per second, this is no more than 60 iterations per second.

To combat this and make it even faster, we can replace requestAnimationFrame(iterate) with the alternative code window.setTimeout(iterate, 0) , which essentially tells the browser to iterate every millisecond that it can, although it can render the page. This method, however, can reduce the frame rate. (for a mobile browser that handles split scrolling like yours, however, frame rate should not be a problem).

Edit:

When I launched a rather simple but long cycle in my desktop browser using my method described above, I got JavaScript measured at 60 frames per second, with about 150 - 200 iterations per second. If you are on a mobile phone, your results are likely to be slower.

Alternative offer:

If you want to use a ready-made API for this kind of thing, there is one that looks pretty cool. The OP found one called Turboid, which makes it easier for you to control this type. http://turboid.net/artikel/real-loops-in-javascript.php

+3
source

Maybe try to wait for the next javascript frame. This can be useful when working with a lot of manipulations with dom:

 setTimeout(function(){ document.body.innerHTML = frag.getElementById('contentRoot').innerHTML; }, 1 ); 
+2
source

Source: https://habr.com/ru/post/1258278/


All Articles