CSS prechody zablokované JavaScriptom


Snažím sa vytvoriť ukazovateľ načítania počas veľmi náročného obdobia JavaScriptu, kde sa vytvárajú a vypĺňajú dosť veľké 3D polia. Tento ukazovateľ načítania musí zostať prázdny, kým používateľ neklikne na tlačidlo.

Zmrazovanie nastáva bez ohľadu na to, či používam -webkit-transition (Táto aplikácia môže byť výlučne pre Chrome, kompatibilita s inými prehliadačmi v mojom prípade nie je potrebná).

Hľadajúc jednoduchosť som si postavil bar takto...

<div id="loader">
    <div id="thumb">
    </div>
</div>

... a potom som sa snažil zvýšiť túto hodnotu v rôznych fázach mojej hlavnej slučky for:

for(i = 0; i < 5 ; i++){
    document.getElementById('thumb').style.width = i*25 + '%';
    //More Code
}

Problém je, že všetko zamrzne, kým JavaScript neskončí. Našiel som podobnú otázku na Stack Overflow, Používanie CSS animácie, zatiaľ čo JavaScript počíta, a v komentároch som našiel a zvážil a/alebo vyskúšal nasledovné:

  • Weboví pracovníci

    Nemyslím si, že to bude fungovať, pretože môj skript plní pole objektmi a konstruktormi obsahujúcimi funkcie, čo podľa tejto stránky nebude fungovať

  • jQuery

    Nie je to možnosť, nemôžem vo svojej aplikácii používať externé knižnice - v každom prípade, importovať celú knižnicu len pre načítavací pruh sa zdá trochu prehnané...

  • Kľúčové snímky

    Toto vyzeralo sľubne a vyskúšal som to, ale nakoniec to tiež zamrzne, takže žiadna radosť

  • timeOut()y

    Premýšľal som o tom, ale keďže účelom načítavacej lišty je znížiť frustráciu, zvýšenie čakacej doby sa zdá byť kontraproduktívne

Bol by som rád za akýkoľvek nárast baru v tejto fáze, aj keby nebol plynulý! Som si celkom istý, že toto je problém, ktorý postihol nielen mňa - možno niekto má zaujímavé riešenie?

P.S.: Zverejňujem to ako novú otázku, namiesto toho, aby som ju pridal k odkazovanej otázke, pretože konkrétne hľadám pomoc s JavaScriptom (nie jQuery) a uprednostnil by som, keby som to mohol získať pomocou prechodu (!=animácia) na šírke.

Odpoveď č. 1

Niektorí ľudia už spomenuli, že by ste mali používať časové limity. To je vhodný prístup, pretože to dá prehliadaču čas „dýchať“ a vykresliť váš pokrokový panel počas úlohy.

Musíte rozdeliť svoj kód, aby pracoval asynchrónne. Povedzme, že momentálne máte niečo takéto:

function doAllTheWork() {
  for(var i = 0; i < reallyBigNumberOfIterations; i++) {
    processorIntensiveTask(i);
  }
}

Potom to musíte premeniť na niečo takéto:

var i = 0;
function doSomeWork() {
  var startTime = Date.now();
  while(i < reallyBigNumberOfIterations && (Date.now() - startTime) < 30) {
    processorIntensiveTask(i);
    i++;
  }

  if(i < reallyBigNumberOfIterations) {
    // Here you update the progress bar
    incrementBar(i / reallyBigNumberOfIterations);

    // Schedule a timeout to continue working on the heavy task
    setTimeout(doSomeWork, 50);
  }
  else {
    taskFinished();
  }
}

function incrementBar(fraction) {
  console.log(Math.round(fraction * 100) + ' percent done');
}

function taskFinished() { console.log('Done!'); }

doSomeWork();

Všimnite si výraz (Date.now() - startTime) < 30. To znamená, že slučka vykoná toľko, koľko môže, počas 30 milisekúnd. Toto číslo môžete zväčšiť, ale čokoľvek nad 100 ms (v podstate 10 snímok za sekundu) bude z pohľadu používateľa začínať pôsobiť pomaly.

Môže byť pravda, že celková úloha bude trvať o niečo dlhšie pri použití tohto prístupu v porovnaní so synchronnou verziou. Avšak z pohľadu používateľa je lepšie mať indikáciu, že niečo sa deje, než čakať neobmedzene, zatiaľ čo sa zdá, že sa nič nedeje - aj keď je táto časť čakania kratšia.

Odpoveď č. 2

Skúsili ste ísť ešte jednoduchšie a vytvoriť funkciu, povedzme:

Pseudonym :

Function increment_bar(amount = 10)
{
 document.getElementById('thumb').style.width = i*amount + '%';
}

Potom odkiaľkoľvek, kde vykonávate svoju spracovateľskú prácu, jednoducho volajte túto funkciu každých x sekúnd alebo kedykoľvek, keď dosiahnete určitý bod v spracovaní (povedzme 10-20 % dokončenia?)

Pseudonym :

{
    Doing_work_here;
    increment_bar(25);
    LOOP
}