Ajax lista válaszidő

Nem hagyott nyugodni a "Gyors adatrögzítés webes felületen" topik. Szerettem volna kipróbálni, hogy tulajdonképpen milyen válaszidőket is lehet elérni manapság böngészőben localhoston futó szerverrel, ha erőfeszítést teszünk bele, hogy kicsi legyen az.

Amolyan programozási kataként írtam egy minimális kliens-szerver keretrendszert, ami legjobb tudásom szerint közelíti az optimálist. (Sima Ajax kérésekkel működik, websocket-tel lehetne még gyorsabbat csinálni, de azt most kihagytam.)

Szöget ütött a fejembe az a megjegyzés, hogy a választó listák nagyon nem optimálisak a böngészőkben, ezért arra csináltam az első mérést. És valóban érdekes eredményt kaptam.

(Firefox 57.0.4 (64-bit)-en mértem, és ezzel a helyi szerverprogrammal: https://github.com/rizsi/quickjs/blob/master/README.md

Szerk: Ubuntu 16.04.3 LTS 64 bites, 2018 jan 10-én napon nagyjából friss volt)

Sima select és option HTML taget használva (Example02) 5000 választható opció körültől már érezhető egy döccenés, 10000 már zavaróan lassú, és 100000 opció másodpercekre megakasztja a futást. Ennyi opcióhoz tehát a beépített select+option nem használható.

Hogyan lehet ennyi elemhez választót csinálni? Egyáltalán hol van a szűk keresztmetszet?

(Józan ésszel persze nyilvánvaló, hogy eleve a görgetősávos választás működésképtelen ennyi elemmen. Valamilyen szöveg alapú szűrőt kell ilyen esetben csinálni, ha egyáltalán felmerül egy jól megtervezett UI-on. De itt most csak a technika határai érdekelnek, nem a UX design.)

A programot módosítgatva kimértem, hogy az adatok átadása JS tömbbe még nem különösebben izzasztó, sőt a DOM objektumok létrehozása sem, csak onnantól, ha be is fűzzük őket a látható fába. Ha kicsit jobban belegondolunk, hogy mit is csinálhat ezzel az adatszerkezettel a browser rá lehet jönni a turpisságra. A browser sorban rajzolja őket, ezért addig nem tudja az n-ediket kirajzolni, ameddig az n-1-ediknek nincs meg az alsó vonala. Ehhez viszont azt ki kell layoutolni! És így tovább a legelsőig vissza. Sőt, eleve a scrollbart sem tudja beméretezni addig, amíg nem layoutolta a teljes listát!

Hogyan lehet ezt workaroundolni? Ha a bejegyzések méreteit előre tudjuk, akkor szorzással kijön a szkrollozandó terület mérete (1 nagy div), és azon belül elegendő az éppen látható soroknak (meg még elől hátul párnak mert miért ne) csinálni egy-egy div-et a megfelelő koordinátákkal, a többit ki lehet dobálni. Tehát az opciók JS memóriában csücsülnek mind, de UI objektum csak a valóban láthatókhoz készül. Ezt valósítja meg a fastscroll.js. Egyelőre fapados, csak egeret kezel, billentyűzetet hozzáhekkelni nem kis munka lenne, de viszonylag triviális.

És mi lett az eredmény?

A beépített select+option használhatósági határa valahol 5000-nél kezd lassulni, és 10000 és 100000 között valahol használhatatlanná válik.

A fastscroll.js-es választó (Example03) 100000 elemet még szemvillanás alatt befrissít. 500000-nél már van egy kis érezhető pillanat befrissítéskor, de a görgetés még itt is látszólag azonnali (ami nem meglepő, mert a görgetés csak a map-ből választás szerint skálázódik az elemszámmal, ami jó esetben N*logN vagy hashmap esetén konstans-szerű). Szintén 500000-nél már megjelenik a szerveroldal is a processzlistában, a listákat ugyanis betesszük a szerver memóriájába is (technikailag persze akár lehetne csak streamelni is, de ezt sem valósítottam most meg).

Jó, de mennyi a vége? 879779. De néha csak 894773. Teljes képernyőn van hogy 894777 lászik, de kicsiben csak 894773. Egyszer láttam 879779-öt is, esküszöm. Szakadékban hátszéllel. Csak nem volt nálam fényképezőgép, de tényleg. Efölött a kis dobozban a szkroll implementáció összeomlik (valami aritmetikai probléma lehet), és a 879779 utáni elemeket nem tudjuk megjeleníteni. Sőt, ha az elemszámot 894785-re vagy nagyobbra állítom, akkor teljesen összeomlik a megjelenítés, és csak az első 6 opció jelenik meg, nem lehet tovább szkrollozni.

Mivel a szkroll omlik össze, ez nyilván(?) függ a dobozmérettől és a sorok magasságától is. A méréseket az olvasóra bízzuk. Fenn van a cucc githubon, sőt a szerver binárisból is letölthető a README-ben leírt helyről.

Képek a végéről:

jó a vége (ugye nullától vannak indexelve az opciók)
Itt már billeg
ennek már rossz vége lett

Hozzászólások

Felteszem, sokban függhet platformtól és az OS renderelési algoritmusaitól. Milyen platformon végzeted?

Ennyi elemnél már autocomplette listenert használnék illetve használok is.
Így az első 2-3 karakter begépelése után nyílik meg a lista benne a már szűkített listával ami kezelhető.
Természetesen a fókusz a listán van enterrel választhat, majd a következő mezőbe lesz a fokusz kijelöléssel, hogy ha méges lenne benne adat akkor egy mozdulattal felülírható legyen.
Eddig nem panaszkodtak.

pch
--
SB-soft online ügyviteli rendszer
--

Jó, de azért "illik", mert 100E opció lassú tud lenni a kliensen. Meg nem feltétlenül akarjuk a hálózatot sem tornáztatni (Ha csak pár betű egy opció, akkor is megabájtos nagyságrendű adat lesz sorosítva.). Meg a szerveren is gyakran lehet spórolni, ha eleve szűrve olvassuk fel az adatot.

De ha a körülmények úgy adódnak, 100E elemet még simán lehet JS memóriában is szűrögetni, elviszi egy mai vas, ahogy a mérés mutatja. Csak UI elemet nem szabad annyit csinálni, mert az már problémás lesz.

Nem az a probléma, hogy "lassú tud lenni" hanem egyszerűen kliens nem arra való, hogy ekkora mennyiségű adatot tároljunk rajta.
És nem csak azért, mert nincs rendes GC jeleneg sem js oldalon. Számolni kell az első betöltés idejével, azzal, hogy gagyi gépekről is fogják az appot használni, ahol sem ram, sem proci nem lesz annyi, hogy tudjanak hatékonyan keresni egy nagyra hízott táblában. Tehát nem kell sajnálni azokat az xhr request-eket a szervertől :)

Jogos, ha valódi usereknek csinálunk oldalt.

Ez a szép a HTML+JS programozásban, hogy ahány projekt, annyiféle a követelmény. Intranetes jellegű fejlesztéseknél például előfordul, hogy csak előre ismert néhány böngészőt kell támogatni, előre ismert hardveren. Ott simán belefér, hogy feldobunk párszáz mega adatot a kliensre.