CSS-övergångar blockerade av JavaScript


Jag försöker skapa en laddningsfält under en mycket intensiv period av JavaScript där ganska tunga 3D-arrayer byggs och fylls. Denna laddningsfält måste förbli tom tills användaren klickar på en knapp.

Frysningen inträffar oavsett om jag använder -webkit-transition (Denna app kan vara exklusiv för Chrome, korsbläddrare är inte nödvändigt i mitt fall).

I jakten på enkelhet har jag byggt min bar så här...

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

... och försökte sedan höja den nivån vid olika steg i min huvud for-loop:

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

Problemet är att allt fryser tills JavaScript är klart. Jag hittade en liknande fråga på Stack Overflow, Using CSS animation while javascript computes, och i kommentarerna fann jag och övervägde och/eller provade följande:

  • WebbArbetare

    Tror inte att det kommer att fungera eftersom mitt skript fyller en array med objekt och konstruktörer som innehåller funktioner vilket enligt den här sidan inte kommer att fungera

  • jQuery

    Inte ett alternativ, jag kan inte använda externa bibliotek i min app - i vilket fall som helst verkar det lite överdrivet att importera ett helt bibliotek bara för en laddningsbar...

  • Nyckelrutor

    Detta verkade lovande och jag provade det, men i slutändan fryser det också, så ingen glädje

  • timeOut()s

    Tänkte på det här, men eftersom poängen med laddningsfältet är att minska frustration, verkar det kontraproduktivt att öka väntetiden

Jag skulle vara glad att få vilken som helst ökning av stapeln i det här skedet, även om det inte är jämnt! Jag är ganska säker på att detta är ett problem som har drabbat fler än bara mig - kanske har någon en intressant lösning?

P.S.: Jag postar detta som en ny fråga istället för att lägga till den i den refererade frågan eftersom jag specifikt söker hjälp med JavaScript (inte jQuery) och skulle föredra om jag kunde få det med en övergång (!=animation) på bredden.

Svar #1

Vissa människor har redan nämnt att du bör använda timeouts. Det är det lämpliga tillvägagångssättet, eftersom det ger webbläsaren tid att "andas" och rendera din progressbar mitt i uppgiften.

Du måste dela upp din kod för att fungera asynkront. Säg att du för närvarande har något som detta:

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

Då behöver du förvandla det till något som detta:

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();

Observera uttrycket (Date.now() - startTime) < 30. Det betyder att loopen kommer att göra så mycket som möjligt under en period av 30 millisekunder. Du kan göra detta nummer större, men allt över 100 ms (i princip 10 bilder per sekund) kommer att börja kännas långsamt ur användarens synvinkel.

Det kan vara sant att den totala uppgiften kommer att ta något längre tid med detta tillvägagångssätt jämfört med den synkrona versionen. Men ur användarens perspektiv är det bättre att ha en indikation på att något händer än att vänta obegränsat medan ingenting verkar hända - även om den senare väntetiden är kortare.

Svar #2

Har du försökt att gå ännu enklare och göra en funktion, låt oss säga:

Alias :

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

Sedan, varifrån du än gör ditt bearbetningsarbete, kan du bara kalla på den funktionen var x:e sekund eller när du når en viss punkt i bearbetningen (säg 10-20% färdigställande?)

Alias :

{
    Doing_work_here;
    increment_bar(25);
    LOOP
}