Rolf B: Kostet Rendern wirklich soooo viel Zeit

Beitrag lesen

Hallo T-Rex,

Kostet Rendern wirklich soooo viel Zeit

Ja. Das tut es.

Ich habe mir eine lokale Bastelseite geschrieben, die in einer PHP Loop 10000 Zeilen raushaut. Das Ergebnis sieht so aus:

<script>
let t0 = Date.now();
</script>
<table>...</table>
<script>
let t1 = Date.now();
window.addEventListener("load", function() {
   let t2 = Date.now();
   console.log(`DOM: ${t1-t0}, 1st event: ${t2-t1}, total: ${t2-t0}`);
});
</script>

Das Eventhandling beginnt erst, wenn die erste Layoutphase vollständig gelaufen ist, d.h. das load Event wartet, bis die Tabelle auf dem Bildschirm ist. Damit kann ich die Zeit für das Rendering nach Aufbau des DOM messen.

Wenn die Tabelle stumpf rausgehauen wird, mit table-layout:auto und ohne feste Spaltenbreiten, habe ich bei mir eine DOM-Zeit von ca 10s. Die Zeit bis zum ersten Event beträgt dann noch 200ms.

Wenn ich über CSS für feste Spaltenbreiten sorge und table-layout:fixed setze, sinkt die Zeit für den DOM-Aufbau auf 6,5s.

Geht das besser? Klar doch:

Wenn ich die Tabelle initial auf display:none setze und das nach Aufbau der Table entferne - etwa so:

<table id="foo" style="display:none">
...
</table>
<script>
  document.getElementById("foo").style.removeProperty("display");
</script>

ändert sich das Timing dramatisch. Das DOM ist dann nach 165ms fertig. Dafür kommt das load-Event erst 3,3s später. In Summe bedeutet das: Es ist nur 1/3 der Zeit vom Anfang. Ich sehe zwar nichts von der Tabelle, bis sie fertig aufgebaut ist, aber genau dieses "nichts sehen = nichts rendern" bringt auch das Tempo.

So richtig fix wird es aber nur, wenn Du auf die Darstellung von 10000 Zeilen komplett verzichtest. Das letzte Beispiel zeigt: Der reine DOM Aufbau ist blitzschnell. Was Zeit kostet, ist die Darstellung auf dem Bildschirm.

Mach also eine CSS-Regel

tr:not(.match) { display:none; }

und programmiere am Client etwas, das dem Anwender nur die benötigten Zeilen zeigt. Zeige nicht mehr als 300 Zeilen an, oder so. Zwinge die Anwender dazu, sich das, was sie brauchen, mit deiner Suchfunktion herauszusuchen.

Du kannst auch einen CSS Paginierer bauen (der von JS angesteuert wird, logischerweise). Dazu musst Du das CSSOM (CSS Objektmodell) verwenden.

Mach Dir diesen style-Abschnitt:

<style id="paginator"> tr { display: none; } tr:nth-child(n+1):nth-child(-n+100) { display: table-row; } </style>

Damit würdest Du die ersten 100 Rows zu sehen bekommen. Wenn Du nun bspw. nicht die Zeilen 1-100, sondern 301-400 anzeigen willst, änderst Du per Javascript den Selektor der zweiten Regel in diesem Abschnitt:

function paginateTo(from, to) {
   let paginationRule = document.getElementById("paginator").style.rules[1];
   paginationRule.selectorText = "tr:nth-child(n+"+from+"):nth-child(-n+"+to+")";
}

Ein Aufruf paginateTo(301,400) würde den Selektor dann passend ändern, auf tr:nth-child(n+301):nth-child(-n+400)`. Das ist jetzt nicht universell, sondern speziell auf's Beispiel zugeschnitten. Eine generische Lösung wäre sicherlich etwas komplizierter.

Eine Mischung von Matching und diesem Paginator funktioniert heute noch nicht, dazu fehlt die of-Option von nth-child (CSS Selectors Level 4). Die ist noch nirgends implementiert. Aber im Zweifelsfall kann man auch von Hand paginieren und sich die passenden Indexe heraussuchen.

Das sind so die Möglichkeiten, wie man die Sache beschleunigen kann. Jedes Rendering, das man weglassen kann, ist ein gutes Rendering.

Rolf

--
sumpsi - posui - obstruxi