Javascript adalah utas tunggal atau multi-utas

Mengembangkan JavaScript untuk halaman web bisa membingungkan. Anda akan mendapatkan kesalahan yang tampaknya tidak masuk akal, Anda akan diberikan nugget saran tentang bagaimana dan kapan Anda dapat menggunakan JavaScript untuk memanipulasi DOM atau membuat permintaan Ajax. Jauh lebih baik untuk memahami alasan aturan ini; . Bagaimana Anda bisa mencapai pemrosesan paralel dan apa cara terbaik?

TL; . ) tidak

Eksekusi program JavaScript apa pun dapat dibagi menjadi dua bagian terpisah

  • Eksekusi awal dari kode yang terjadi selama pemuatan halaman
  • Penanganan acara selanjutnya

Eksekusi kode awal

Kami memiliki, misalnya, halaman web dengan beberapa kode JavaScript sebaris dan beberapa referensi ke pustaka JavaScript. Bagaimana kode JS dieksekusi di halaman ini? . Saat file ini dimuat, kita dapat membayangkan bahwa kode JS ini dibungkus dengan fungsi anonim. Fungsi imajiner ini memiliki ruang lingkup global sebagai ruang lingkup fungsinya sendiri dan dapat dijalankan sendiri. Kita bisa membayangkannya sebagai potongan kode berikut

1

2

3

(fungsi () {

    // konten file JS ada di sini

})();

Contoh berikutnya menunjukkan kepada kita bahwa kode JavaScript dieksekusi sesegera mungkin setelah elemen inline atau referensi file ditemukan, sehingga tidak menunggu pembuatan pohon DOM selesai (JSFiddle link): Kode JavaScript sebaris dijalankan dengan cara yang sama, tetapi tanpa fase pemuatan file. Penting untuk diketahui bahwa, selama eksekusi kode ini, baik pembuatan DOM maupun perenderan laman dijeda. Akibatnya, pengguna melihat halaman kosong dan harus menunggu.

1

2

3

4

5

    var divElement = dokumen.getElementById('someId');

    divElement. innerText = 'Halo, dunia. '

<div id="someId"></div>

Cara lain untuk menangani pemuatan file JS adalah dengan menggunakan “ async ” dan “ defer ” attributes for the script element. If you don’t know about these attributes or want to know a little bit more about how to load external scripts, please read this great artikel yang bagus ini. Seperti yang Anda lihat, kami mencoba mengakses elemen divisi (DIV) yang ditempatkan setelah blok skrip. Dalam contoh ini kita akan mendapatkan pengecualian karena variabel divElement adalah null. Untuk menghindari kode JavaScript mencoba mengakses elemen DOM yang tidak dapat dijangkau, Anda pasti perlu menempatkan kode Anda di akhir halaman atau setidaknya menjalankannya setelah halaman dimuat.

Putaran acara

Eksekusi kode awal berakhir setelah halaman dimuat dan kode JavaScript awal telah berjalan, semua penangan peristiwa dilampirkan, semua permintaan AJAX dikirim dan pengamatan kami diamati. Lalu mengapa kita tidak menangani semua acara langganan kita dengan cara paralel kuno? . ini karena pohon DOM tidak aman untuk thread dan akan berantakan jika kami mencoba melakukannya. Karena keterbatasan ini, semua kode JavaScript kita harus dijalankan dalam satu utas, sementara pada saat yang sama memastikan bahwa kode tersebut menangani semua peristiwa dan tidak kehilangan panggilan balik apa pun. Untuk alasan ini kami datang ke loop Acara

Perulangan peristiwa dapat dibayangkan sebagai alur proses berikut

Javascript adalah utas tunggal atau multi-utas

Seperti yang dijelaskan dalam gambar, bagian utama dari JavaScript Event loop adalah

  • Tumpukan Panggilan, yang merupakan tumpukan panggilan biasa yang berisi semua fungsi yang dipanggil
  • Antrean penangan acara, antrean penangan acara yang menunggu untuk dieksekusi
  • The Event loop, yang merupakan proses yang memeriksa apakah event handler antrian tidak kosong dan jika itu - panggilan atas event handler dan menghapusnya dari antrian
  • API Web JavaScript. API yang disediakan oleh browser yang bertanggung jawab untuk mengisi antrian Event handler, menyediakan banyak fitur seperti kemampuan untuk membuat permintaan AJAX dan e. g. implementasi Mozilla memiliki dokumentasi yang bagus tentang API Web dan dapat ditemukan melalui tautan

Setiap jendela atau WebWorker memiliki loop acaranya sendiri. Kita dapat membayangkan bahwa setiap konteks JS membungkus semua kode dengan potongan kode berikut

1

2

3

4

5

sementara (benar) {

    jika (eventHandlersQueue. isNotEmpty()) {

        eventHandlersQueue. processTopEventHandler();

    }

}

Tetapi mengapa halaman tidak merespons selama eksekusi JavaScript? Tentu saja, model loop Peristiwa seperti yang dijelaskan adalah abstraksi yang sangat disederhanakan dari apa yang sebenarnya terjadi di balik tudung . Implementasi sebenarnya dapat bervariasi dari browser ke browser, tetapi prinsip utamanya sama. Jika Anda ingin mendapatkan informasi yang lebih akurat tentang loop Acara, Anda dapat membaca bagian yang sesuai dari spesifikasi HTML WHATWG, yang dapat Anda temukan di.

Sejauh ini, saya telah menjelaskan bagaimana kode JavaScript kita dieksekusi selama pemuatan halaman, dan bagaimana berbagai event ditangani oleh loop Event. Kami juga tahu bahwa kami tidak ingin mengubah pohon DOM di utas yang berbeda. Tapi bagaimana dengan potongan kode ini (tautan JSFiddle)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

fungsi menghitungPi(jumlahIterasi) {

    var pi = 0,

      n = 1;

    untuk (var i = 1; i < numberOfIterations; i++) {

        pi = pi + (4 / n) - (4 / (n + 2));

        n += 4

    }

 

    kembalikan pi;

};

 

blockUIButton. klik = fungsi () {

    hasil perhitungan. innerHTML = menghitungPi(1000000000);

}

Ini semua karena reflow. Reflow adalah proses perhitungan ulang setiap posisi elemen, gaya dan karakteristik lainnya yang diperlukan untuk rendering halaman yang tepat. Ini dipicu dengan menambahkan elemen DOM baru, mengubah ukuran jendela, atau mengubah gaya elemen dari JavaScript. Proses reflow ini rumit dan dapat memperlambat perenderan halaman secara signifikan. Namun akan lebih buruk lagi jika, setelah setiap perubahan posisi, kami harus merender halaman. Dalam hal ini, pengguna akan melihat semua langkah pembuatan halaman hingga hasil akhir, tetapi kami tidak menginginkan perilaku seperti itu. Saya telah membuat tes kecil untuk menunjukkan bagaimana reflow menyebabkan kinerja buruk, yang dapat Anda temukan melalui tautan ini. Selama eksekusi kode ini, halaman diblokir sehingga pengguna tidak dapat berinteraksi dengan halaman. Beberapa browser bahkan meminta pengguna untuk menunggu hingga halaman tersebut mengakhiri perhitungannya atau menghentikan prosesnya.

Satu hal lagi yang perlu disebutkan adalah bahwa render halaman memiliki prioritas lebih tinggi daripada penangan mana pun yang menunggu dalam antrean penangan peristiwa. Browser cenderung merender halaman 60 bingkai per detik atau, dengan kata lain, satu bingkai kira-kira setiap 16 milidetik. Saat tumpukan panggilan dihapus, browser memeriksa apakah sudah waktunya merender halaman. baru setelah itu memeriksa antrian Event handler. Mempertimbangkan informasi baru ini, loop Acara kami yang dikodekan secara abstrak diperpanjang dengan pemeriksaan terkait render

1

2

3

4

5

6

7

8

9

sementara(benar){

    jika(renderEngine. isItTimeToRender(){

        renderEngine. render();

    }

 

    jika(eventHandlersQueue. isNotEmpty()){

        eventHandlersQueue. processTopEventHandler();

    }

}

Di desktop, sulit untuk melihat bagian render dari loop peristiwa, tetapi dapat terlihat di perangkat seluler yang sumber dayanya lebih terbatas

Bagaimana dengan kode asinkron dalam JavaScript?

Semua kode asinkron dalam JavaScript didasarkan pada API Web yang disediakan oleh browser. Ini bervariasi pada fungsionalitas dan tujuan, tetapi semuanya memberikan kemungkinan untuk menjalankan fungsi panggilan balik. Kami dapat membedakan dua kelompok API tersebut

Grup besar pertama terdiri dari API yang mengaktifkan panggilan balik setelah beberapa pekerjaan selesai. Itu bisa menangani permintaan AJAX, penangan onload dalam DOM atau mungkin respons pekerja web. Callback diaktifkan ketika sesuatu berubah, dan tujuan callback ini adalah untuk bereaksi terhadap perubahan ini. Saat callback harus dijalankan, callback ditambahkan ke antrean Event handler

Kelompok kedua mencakup fungsi setTimeout(callback, time) dan setInterval(callback, time). Bagi mereka yang tidak pernah menghadapi fungsi ini saya harus menjelaskan

  • setTimeout – menjalankan callback sekali setelah jumlah waktu yang ditentukan
  • setInterval – menjalankan callback pada interval waktu tertentu

Fungsi-fungsi ini tidak bereaksi terhadap perubahan, tetapi hanya menjalankan kode kita. Salah satu tujuan utama mereka adalah memberi kita sarana untuk memecah eksekusi sinkron menjadi bagian-bagian asinkron. Penting untuk diingat bahwa fungsi ini tidak menjamin bahwa panggilan balik akan dijalankan setelah jumlah waktu yang Anda tentukan. Mereka menjamin bahwa callback akan ditambahkan ke antrean Event handler, tetapi, seperti yang kita ketahui, handler sudah menunggu eksekusi. Jadi, argumen "waktu" harus diperlakukan sebagai "tidak lebih awal dari, tetapi setelah waktu yang ditentukan"

Cara mencapai paralelisme dalam JavaScript

Saya telah menyebutkan bahwa JavaScript adalah single-threaded dalam konteks eksekusi yang sama. Karena itu kami memiliki dua opsi untuk mencapai paralelisme dalam JavaScript

Opsi pertama adalah pseudo-paralelisme berdasarkan fungsi setTimeout. Ide utamanya adalah untuk membuka blokir interaksi pengguna dengan antarmuka, tetapi, pada saat yang sama, mengeksekusi logika yang diperlukan untuk dieksekusi. Pendekatan ini didasarkan pada pemecahan eksekusi menjadi beberapa bagian. Kode berikut menunjukkan implementasi dari pendekatan ini (tautan JSFiddle)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

fungsi appendResult(hasil) {

    var div = dokumen.buatElemen('div');

    div. innerText = hasil;

    hasil. appendChild(div);

}

 

fungsi menghitungPi(pi, n) {

    untuk (; ; n += 4) {

        pi = pi + (4 / n) - (4 / (n + 2));

 

        jika ((n - 1) % 20000000 == 0) {

            appendResult(pi);

            setTimeout(fungsi () {

                menghitungPi(pi, n + 4);

            });

            kembalikan;

        }

    }

}

 

mulai Perhitungan. klik = fungsi () {

    menghitungPi(0, 1);

}

Opsi kedua adalah menggunakan WebWorkers. WebWorkers mewakili konsep utas paralel dalam JavaScript, tetapi dengan beberapa batasan. Dalam contoh ini, perhitungan dibagi menjadi blok-blok terpisah sehingga pengguna dapat berinteraksi dengan antarmuka antara eksekusi blok-blok ini.

  • Tidak mungkin mengakses elemen DOM di dalam instance pekerja web. Sebenarnya Anda dilarang memberikan referensi apa pun ke struktur DOM dan fungsi terkaitnya
  • Komunikasi dengan pekerja didasarkan pada pesan melalui metode postMessage() dan event “message”.
  • Tidak ada jendela, dokumen, dan objek induk di dalam pekerja

Semua batasan ini ditambahkan untuk memblokir kemungkinan mengubah DOM, yang tidak aman untuk thread, dari dalam pekerja. Penggunaan utama pekerja adalah untuk perhitungan latar belakang yang berat. Contoh berikut menunjukkan cara menggunakan pekerja untuk perhitungan π (tautan JSFiddle)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

// Beberapa keajaiban untuk menjalankan fungsi sebagai WebWorker

var workerBlob = baru Blob(["(" + worker.toString() + " . ], { type: 'text/javascript' }),

    workerInstance;

 

Tombol Mulai. klik = fungsi () {

    jika (workerInstance) {

        workerInstance. berhenti();

    }

 

    keluaran. innerHTML = "";

    workerInstance = baru Worker(URL.createObjectURL(workerBlob));

    workerInstance. onmessage = fungsi (e) {

        keluaran. innerHTML += " + e.data + '';

    };

    workerInstance. postMessage(null);

};

 

fungsi pekerja() {

    onmessage = fungsi (e) {

        var pi = 0,

              n = 1;

        untuk (var n = 1; ; n += 4) {

            pi = pi + (4 / n) - (4 / (n + 2));

 

             jika ((n - 1) % 200000000 == 0) {

                postMessage(pi);

 

              }

        }

    };

}

Jika Anda perlu memproses data dalam jumlah besar atau membuat perhitungan berat dan tidak perlu mendukung browser versi lama, maka saya sarankan Anda menggunakan . Namun, jika Anda hanya perlu menangani kumpulan objek dan Anda dapat mengorbankan beberapa waktu untuk membuka kunci antarmuka untuk interaksi pengguna, maka Anda dapat menggunakan paralelisme semu berdasarkan because of their performance and real implementation of parallelism. But, if you just need to handle a collection of objects and you can sacrifice some time to unlock interface for user interaction, then you can use pseudo-parallelism based on setTimeout . I have prepared a small performance comparison that you can play with by the tautan . Selama eksekusi pekerja, pengulangan Peristiwa utama tidak pernah diblokir; .

Kesimpulan

Menjawab pertanyaan, JavaScript adalah single-threaded dalam konteks yang sama, tetapi API Web browser tidak. Kami juga memiliki kemungkinan mensimulasikan paralelisme dengan menggunakan fungsi setTimeout atau, dengan beberapa batasan, dengan menggunakan paralelisme nyata yang disediakan oleh WebWorkers

Javascript adalah utas tunggal atau multi-utas

Goodness Woke 25 November 2022

Javascript adalah utas tunggal atau multi-utas

Goodness Woke 25 November 2022

Cepat. js atau Selanjutnya. js untuk Proyek Backend Anda

7

  • JavaScript

Pada artikel ini, saya akan memperkenalkan dua framework JavaScript yang dapat digunakan untuk membangun proyek backend. Pengembangan backend adalah pengembangan logika sisi server yang memberdayakan situs web dan aplikasi dari balik layar. Ini biasanya mencakup semua kode yang diperlukan untuk membangun database, server, dan aplikasi. Dari migrasi basis data ke integrasi API untuk menyiapkan teknologi sisi server yang membuat situs web tergerak. … Baca lebih banyak

Apakah JavaScript multithreaded atau single threaded?

js menjalankan kode JavaScript dalam utas tunggal , artinya kode Anda hanya dapat melakukan satu tugas dalam satu waktu.

Bisakah JavaScript menjadi multithreaded?

Berkat kemajuan terbaru dalam bahasa--seperti objek Atomics dan SharedArrayBuffers dan Pekerja Web di browser-- JavaScript sekarang menjadi bahasa multi-utas. These features will go down as being the biggest paradigm shift for the world's most popular programming language.

Apakah JavaScript adalah utas tunggal?

Dalam konteks pemrograman, Paralelisme adalah pemanfaatan banyak utas dalam sistem operasi. Rutinitas dapat berjalan pada waktu yang sama terlepas dari urutan eksekusi. Namun, JavaScript adalah utas tunggal dan hanya satu baris kode yang dapat dieksekusi pada waktu tertentu .