Dom iterando causando la mitad de renderizado de webview
Im usando android para abrir un archivo web local y luego iterar la dom y aplicar algunos cambios, pero mientras iterating la webview stop para hacer la página en alguna parte aleatoria, mira el gif:
Lo que ya hice
- Cómo incrustar una fuente personalizada en la aplicación de Android (WebView)
- Android: muestra .mht o .mhtml en la vista Web en la aplicación
- Android WebView desplazamiento suave
- WebView con vídeo incorporado reproduce en segundo plano
- Reproducción de archivos de audio locales en la aplicación de visualización web de Android
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 }
Y ahora para evitar los problemas de procesamiento en cada cambio de dom, creé un documento y cambiar el dom en él (o simplemente iterar) y devolver su html al documento principal
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
¿Hay una manera de mantener la representación normal sin "cortarla"?
PS: im usando la función para iterar en el window.onload, por lo que sólo comienza DESPUÉS de todos los dom se carga en el navegador, ¿por qué seguir cortándolo? Y sólo volver a hacer al final de la iteración?
- Cómo configurar el zoom / ancho inicial para una vista web
- Jellybean / ICS Método de publicación HTTP Android + WebView.RestoreState
- Android: gran aumento de tamaño de apk cuando se utiliza el navegador de cruce de peatones
- La vista web de Android conserva los datos del formulario cuando cambia la orientación
- Rellenar campos en la vista web de forma automática
- Proguard rompe Android WebView, ¿Por qué?
- Habilitación de la compatibilidad con WebGL para Android WebView
- La página Web Gujarati no se muestra perfecta en la vista Web
El problema con JavaScript es que mientras JavaScript está en ejecución, toda la página está congelada y no renderiza nada. Si usted tiene un muy grande para el funcionamiento del lazo, esto explica su edición.
La mayoría de los navegadores de computadoras de escritorio renderizarán el desplazamiento al mismo tiempo que renderizar la página (apuesto a que si ejecuta esta página en un navegador de escritorio, ni siquiera te permitiría desplazarte).
Sin embargo, la mayoría de los dispositivos móviles, en un esfuerzo por verse rápidos y lisos, harán que el desplazamiento se separe de la propia página. El problema con esto es que si JavaScript está atascado ejecutando un bucle muy largo, el usuario será capaz de desplazarse, pero la página no renderizará por delante de ellos, llegando finalmente a esta zona en blanco donde todavía no se ha procesado nada.
Apuesto a que si has intentado acercar la página mientras la función está en ejecución, se vería muy borrosa, porque no se está realizando ninguna renderización.
Una forma de solucionar este problema es utilizando temporizadores o la API requestAnimationFrame.
requestAnimationFrame
es compatible con casi todos los navegadores modernos. Lo que hace es poner código hasta que el siguiente fotograma se procese y se utiliza comúnmente para hacer animaciones suaves.
Usando esta API, he creado el siguiente código …
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();
Ahora, el código anterior ejecuta una iteración de su bucle for cada marco de animación. Suponiendo que su dispositivo funcione a 60fps, esto hace un máximo de 60 iteraciones por segundo.
Para combatir esto y hacerlo aún más rápido, podemos reemplazar requestAnimationFrame(iterate)
con el código alternativo window.setTimeout(iterate, 0)
, que esencialmente le dice al navegador que haga una iteración cada milisegundo que pueda, mientras pueda procesar la página . Sin embargo, este método puede reducir la velocidad de fotogramas. (Para un navegador móvil que maneja scrolling separado como el tuyo, sin embargo, el framerate no debería ser un problema)
Editar:
Cuando ejecuté un bucle bastante simple, pero largo, en mi navegador de escritorio con mi método anterior, logré una 60fps medida con JavaScript, con alrededor de 150 a 200 iteraciones por segundo. Si estás en el móvil, tus resultados probablemente serán más lentos.
Sugerencia alternativa:
Si desea utilizar una API pre-construida para este tipo de cosas, hay una por ahí que se ve muy bien. El OP encontró uno llamado Turboid, que le permite gestionar este tipo de bucle más fácilmente. http://turboid.net/artikel/real-loops-in-javascript.php
Tal vez trate de esperar para el siguiente marco de javascript, puede ser útil cuando se trata de una gran cantidad de dom manipulación:
setTimeout(function(){ document.body.innerHTML = frag.getElementById('contentRoot').innerHTML; }, 1 );
- Cómo crear un nuevo RealmObject que contiene una RealmList
- Android layout-land y manejo de rotación de pantalla