Transisi CSS diblokir oleh JavaScript


Saya sedang mencoba membuat bilah pemuatan selama periode JavaScript yang sangat intensif di mana beberapa array 3d yang cukup berat dibuat dan diisi. Bilah pemuatan ini perlu tetap kosong hingga pengguna mengeklik tombol.

Pembekuan terjadi baik saya menggunakan atau tidak -webkit-transition (Aplikasi ini bisa khusus untuk Chrome, lintas browser tidak perlu dalam kasus saya).

Mencari kesederhanaan, saya membangun bar saya seperti ini...

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

... dan kemudian berusaha meningkatkan batas itu pada berbagai tahap dari loop for utama saya:

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

Masalahnya adalah semuanya membeku sampai JavaScript selesai. Saya menemukan pertanyaan serupa di Stack Overflow, Menggunakan animasi CSS sementara JavaScript sedang menghitung, dan di komentar saya menemukan dan mempertimbangkan dan/atau mencoba hal-hal berikut:

  • Pekerja Web

    Jangan kira itu akan berhasil karena skrip saya sedang mengisi array dengan objek dan konstruktor yang berisi fungsi yang menurut situs ini tidak akan berhasil

  • jQuery

    Bukan pilihan, saya tidak bisa menggunakan pustaka eksternal di aplikasi saya - dalam hal apapun, mengimpor seluruh pustaka hanya untuk bilah pemuatan terasa berlebihan...

  • Keyframes

    Ini menjanjikan dan saya mencobanya, tetapi pada akhirnya juga membeku, jadi tidak ada kegembiraan

  • timeOut()

    Pernah terpikirkan tentang ini, tapi karena tujuan dari bilah pemuatan adalah untuk mengurangi frustrasi, menambah waktu tunggu tampaknya bertentangan dengan tujuan

Saya akan senang mendapatkan apa pun peningkatan pada bar di tahap ini, meskipun itu tidak mulus! Saya cukup yakin ini adalah masalah yang telah dialami bukan hanya oleh saya - mungkin seseorang memiliki solusi yang menarik?

P.S.: Saya memposting ini sebagai pertanyaan baru daripada menambahkan ke pertanyaan yang dirujuk karena saya secara khusus mencari bantuan dengan JavaScript (bukan jQuery) dan lebih memilih jika saya bisa mendapatkannya menggunakan transisi (!=animasi) pada lebar.

Jawaban #1

Beberapa orang sudah menyebutkan bahwa Anda sebaiknya menggunakan timeout. Itulah pendekatan yang tepat, karena itu akan memberi browser waktu untuk "bernapas" dan merender bilah progres Anda di tengah tugas.

Anda harus membagi kode Anda agar bekerja secara asinkron. Misalnya saat ini Anda memiliki sesuatu seperti ini:

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

Lalu Anda perlu mengubahnya menjadi sesuatu seperti ini:

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

Perhatikan ekspresi (Date.now() - startTime) < 30. Itu berarti loop akan menyelesaikan sebanyak mungkin dalam rentang 30 milidetik. Anda bisa membuat angka ini lebih besar, tetapi apa pun di atas 100ms (pada dasarnya 10 frame per detik) akan mulai terasa lambat dari sudut pandang pengguna.

Mungkin benar bahwa keseluruhan tugas akan membutuhkan waktu sedikit lebih lama menggunakan pendekatan ini dibandingkan dengan versi sinkron. Namun, dari pengalaman pengguna, memiliki indikasi bahwa sesuatu sedang terjadi lebih baik daripada menunggu tanpa batas sementara tidak ada yang tampak terjadi - bahkan jika waktu tunggu yang terakhir lebih singkat.

Jawaban #2

Apakah Anda sudah mencoba membuatnya lebih sederhana lagi dengan membuat sebuah fungsi, misalnya:

Nama samaran :

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

Kemudian dari mana pun Anda melakukan pekerjaan pemrosesan Anda, cukup panggil fungsi itu setiap x detik atau setiap kali Anda mencapai titik tertentu dalam pemrosesan (misalnya 10-20% penyelesaian?)

Nama samaran :

{
    Doing_work_here;
    increment_bar(25);
    LOOP
}