Admin:Javascript optimalisaties

Uit wiki.openbomenkaart.org
Naar navigatie springen Naar zoeken springen

De website draait op javascript

Inleiding

Deze pagina behandelt een aantal optimalisaties, deels gereed, deels nog te implementeren. (stand van 29 mei 2022).

Doelen zijn:

  • Opstarttijd minimaliseren
  • Navigatie soepel laten verlopen
  • Waar mogelijk zonder dat dit ten koste gaat van functionaliteit
  • Waar mogelijk zonder dat dit de voorbereiding van bomenbestanden compliceert

Deze doelen zijn deels tegenstrijdig, compromissen zijn onvermijdbaar. Om een voorbeeld te geven: het zou in principe mogelijk zijn veel data verificatie en normalisatie uit te voeren in een voorbereidingsstap. En ook data compacter te maken, door met coderingen te werken (al zal automatische compressie hier het meeste werk al doen (?)). Maar dat maakt het voorbereiden van de invoerbestanden complexer (en kwetsbaarder, meer kansen om fouten maken). Nu kan een bomenbestand dat met Overpass uit de OSM database is gehaald, rechtstreeks door de script ingelezen worden.

We streven naar een web site die het geduld van de gebruiker niet op de proef stelt. Gelijkertijd zijn we optimistisch dat voortschrijdende ontwikkelingen op het gebied van snellere hardware en snellere data tranfers ons ook in de kaart zullen spelen ;-)

Ik zal een aantal optimalisaties bespreken en hun effekt meten in een lokale testomgeving (zonder dat er bestanden van een web site hoeven te worden opgehaald, zoals *.html, *.json, *.js, *.css, .*jpg, *.png, etc). Tenzij anders vermeld zal ik de tests draaien op mijn NUC PC (Intel Core i7-1165G7 Processor, 24GB mem, 2TB SSD)

Veel script code

Er is heel veel script code, in aantal regels gemeten is dat ± .... (?) Alleen dat maakt het opstarten al merkbaar trager: die code moet eerst geinterpreteerd worden. Juist bij een klein json bestand zal die tijd om het script te parsen relatief zwaar wegen. Ik zal tests doen met de lokale versie van de OBK kaart voor Het Plantsoen

Grootte invoerbestanden

± 260.000 bomen in Amsterdam

Het grootste invoerbestand is nu de json file voor Amsterdam, die met 70 MB echt gigantisch genoemd mag worden. trees_amsterdam.json bevat ± 250.000 bomen. Dit bestand staat nog niet online op OBK. Maar het is als extreem voorbeeld wel een geschikte kandidaat om optimalisaties te testen. Ook hier testen we dus weer met alle files lokaal beschikbaar.

Voor o.a. Den Haag zijn er deelkaarten. Voor Leiden is er naast de superkleine kaarten per park alleen de hele kaart ineens: ± 80.000 bomen. Qua performance lijkt 80k bomen ineens binnenhalen nu wel doenlijk, mogelijk door al eerder gerealiseerde optimalisaties.

Andere grote bomenkaarten zijn bijv. die voor Ottawa, met ± 150.000 bomen, en die voor Parijs, met ± 94.000 bomen. (Kaarten buiten Nederland worden momenteel -media 2022- niet actief onderhouden). Voor Parijs had ik al aparte deelkaarten voor steeds enkele arrondissementen, om zo de opstarttijd te beperken.

Grootte bestanden terugbrengen

  • To do ??
Het zou mogelijk zijn de grootste bestanden in delen te downloaden, met progress indicator. Maar dat compliceert weer, heb ik dus nog niet voor gekozen.
  • Ready
Andere mogelijkheid is middels een perl script alle content die de scripts niet nodig hebben vooraf uit het json bestand te filteren. Dat zou dan alleen voor de grootste bestanden hoeven te gebeuren en is soewieso optioneel. Het script functioneert met of zonder de nodeloze tags. Perl script https://openbomenkaart.org/scripts/perl/compact.pl dient daartoe.
trees_amsterdam.json kan op deze manier verkleind worden van 70MB naar 49MB
  • Test
Voor bestanden die uit meerdere bronnen geaggregeerd worden (nu is dat alleen trees_leiden.json kan die filter functie toegevoegd worden aan https://openbomenkaart.org/scripts/perl/csv2json.pl die sowieso gedraaid moet worden. De winst is echter gering (paar %) als meeste bomen uit csv bestand komen (gemeentebestand) en slecht enkele honderden uit osm (overpass).


Progress bar

  • To do ??
Tijdens het downloaden een progress bar tonen zal ongeduld deel wegnemen. Nu wordt er pas voortgang getoond als de file gedownload is en het parsen begonnen is. Er is code voor een progress bar, maar staat op non-actief. Weer actief maken?

Code voor taxonomie intern cachen

Test

taxonomische namen, in meerdere talen

3 scenario's:
1 Amsterdam kaart, zonder caching

2 Amsterdam kaart, met caching per boomsoort, uitsplitsen in hover en popup html via dure regexps, na ophalen uit de cache

3 Amsterdam kaart, met caching per boomsoort, dupliceren en uitsplitsen via .split() dure regexps zijn al gedaan in buildHtmlTaxonManyLang en worden per boomsoort dus maar 1 keer gedaan

Resultaat van scenario 1 naar 3, van 18,5 naar 11 seconden (lokaal getest).


Het stuk html dat hieraan ten grondslag ligt werd eerst voor elke boom (dus voor elke hover en popup box) opnieuw gegenereerd in functie buildAndStoreHtmlBoxes (build.js) met data uit grote tabellen (taxon_names.js). Echter: sommige bomen komen wel heel vaak voor: in Amsterdam de Platanus hispanica 14.702 keer!

Nu wordt deze data intern gecached in array cache_taxon_html. De rest van de dialoog box bevat variabele elementen (metrics, ref_id, etc), dus dit gebeurt alleen voor het taxonomische deel.

Zoals het nu werkt wordt de data per taxon zo opgeslagen dat daaruit zowel de html voor de hover box (die beperkter is), als voor de dialoog box geextraheerd kan worden. Dit gebeurt met ook weer zware regular expressions. Misschien zijn aparte caches voor beide typen boxen nog efficienter. Maar dat alles wordt mogelijk achterhaald, wanneer de beste optimalisatie doorgang vindt (zie onder).

(Juni 2022) Inmiddels is de code verder geoptimaliseerd. Nu wordt in buildHtmlTaxonManyLang de code voor hover en popup boxen gegenereerd, dan gedupliceerd, dan geoptimaliseerd met regular expressions voor apart hover en popup boxen, dan in cache opgeslagen voor hergebruik. (To do: simplificatie?) Mogelijk ga ik de code verder vereenvoudigen, en parametergestuurd de twee varianten (voor dus hover en popup boxen) apart aanmaken, en het strippen met regular expressions geheel verwijderen. Dit vooral om maintenance eenvoudiger te maken.

Plaatjes later laden

Test

Icon index en tellingen.png

  
met en zonder uitgestelde activatie zijpaneel
met en zonder gesimuleerde lagere bandbreedte (throttling)

Eerst werd het zijpaneel, met kleine afbeeldingen voor elk genus, bij opstarten meteen aangemaakt, al is dan het nog niet meteen zichtbaar. Nu wordt dit uitgesteld tot de gebruiker het ikoon 'Index en tellingen' aanklikt. Dat scheelt weer ±180 kleine afbeeldingen (Amsterdam) bij initiele opstarttijd.

N.B. bij tab Network loopt het aantal requests steeds verder op als het zijpaneel telkens weer getoond en dan weer weggeklikt wordt, maar alleen als Disable cache actief is. Is wel logisch, geen beletsel in een real-life situatie.

Initieel maar 1 tileset laden

Test

meerdere tilesets laden door elkaar heen


Het verbaasde me al lange tijd dat er meerdere tilesets tegelijk geladen werden, die deels door elkaar getoond werden tot alles binnen was. Altijd gedacht dat dat vast heel makkelijk anders kon, maar zoveel dingen waar nog aan gewerkt moest worden. Nu blijkt het 1 regel code om dat niet te laten gebeuren. En toch worden bij het wisselen van kaart de nieuwe tiles probleemloos en snel geladen, alsof ze er al waren.

Chrome debug - tab Sources
3 tilesets
Chrome debug - tab Sources
1 tileset
Chrome debug - tab Network
1 vs 3 tilesets
local vs remote vs throttling

Functie createTileLayer (in tileservers.js)

 var layer = L.tileLayer (tileservers [use_tileserver].url, 
 {
   ....
 }).addTo(map); 

=>

 var layer = L.tileLayer (tileservers [use_tileserver].url, 
 {
   ....
 }) ; // .addTo(map); disabling 'addTo (map)' makes that only tiles for one layer are retrieved initially

Beste optimalisatie !!!

To do

De beste optimalisatie moet nog ingevoerd worden. Nu worden alle dialoogboxen vooraf gegenereerd en elk in html-vorm aan Leaflet aangeboden. Dat zijn in het geval van Amsterdam 260,000 hover- en 260.000 popup boxen. Leaflet heeft dan alles kant en klaar bij de hand als een gebruiker over een cirkel gaat met de muis (hover) of die cirkel aanklikt. Maar dat neemt heel veel geheugen en vertraagt het opstarten aanzienlijk. Het zou toch veel mooier zijn als Leaflet bij elke cirkel een indexnummer opslaat, en pas bij hover over of klik op de cirkel de dialoogbox gegenereerd wordt.

Technisch detail: Nu werkt dat nog niet. Zie addEventHandlers (in main.js). Dit is omdat mijn script pas de controle krijgt nadat de dialoogbox al getoond is, bij een tweede maal hover of click zie je dan de box als bedoeld, maar dat is te laat. Ik zoek nog naar een oplossing maar dat valt niet mee, kan ook geen goed voorbeeld op het web vinden. Naast 'popupopen' en 'tooltipopen' is er ook de event 'mouseover' die in ieder geval eerder binnen komt dan de eerste twee. Maar daar heb je weer geen toegang (voor zover ik nu weet) tot de html tekst, die je wilt updaten.


Tot slot

Een deel van de code is complex, maar goed gestructureerd. een deel van de code is complex, en niet zo goed gestructureerd. Daar ligt nog een uitdaging.