Kapan JavaScript disinkronkan?


202

Saya mendapat kesan bahwa JavaScript selalu asinkron. Namun, saya telah belajar bahwa ada situasi di mana tidak (manipulasi DOM). Apakah ada referensi yang bagus di mana saja tentang kapan akan sinkron dan kapan akan sinkron? Apakah jQuery memengaruhi ini sama sekali?


14
Selalu dengan pengecualian ajax.
defau1t

Jawaban yang diterima salah, dan menyesatkan, silakan periksa.
Suraj Jain

2
Juga bermanfaat menonton youtube.com/watch?v=8aGhZQkoFbQ untuk memahami loop acara, dan bagaimana tumpukan, API web, dan tugas antrian bekerja berkaitan dengan sinkronisasi dan async
mtpultz

1
@ defau1t Bukankah ini salah, JavaScript selalu sinkron, ketika ajax panggilan selesai callback berakhir di antrian, bagaimana pengecualian untuk sifat sinkron dari skrip java.
Suraj Jain

Jawaban:


281

JavaScript selalu sinkron dan berulir tunggal. Jika Anda menjalankan blok kode JavaScript pada halaman, maka tidak ada JavaScript lain pada halaman itu yang saat ini akan dieksekusi.

JavaScript hanya asinkron dalam arti dapat dibuat, misalnya, panggilan Ajax. Panggilan Ajax akan berhenti mengeksekusi dan kode lain akan dapat dijalankan sampai panggilan kembali (berhasil atau tidak), pada saat mana panggilan balik akan berjalan secara sinkron. Tidak ada kode lain yang akan berjalan pada saat ini. Itu tidak akan mengganggu kode lain yang sedang berjalan.

Pengatur waktu JavaScript beroperasi dengan jenis panggilan balik yang sama.

Menggambarkan JavaScript sebagai asinkron mungkin menyesatkan. Lebih akurat untuk mengatakan bahwa JavaScript sinkron dan berulir tunggal dengan berbagai mekanisme panggilan balik.

jQuery memiliki opsi pada panggilan Ajax untuk membuatnya secara sinkron (dengan async: falseopsi). Pemula mungkin tergoda untuk menggunakan ini secara tidak benar karena memungkinkan model pemrograman yang lebih tradisional sehingga orang mungkin lebih terbiasa. Alasannya bermasalah adalah bahwa opsi ini akan memblokir semua JavaScript pada halaman sampai selesai, termasuk semua penangan acara dan timer.


31
maaf, saya tidak mengerti pernyataan ini "Kode akan berhenti dieksekusi sampai panggilan kembali (berhasil atau salah)". bisakah kamu menguraikan. Bagaimana pernyataan itu benar ketika Anda juga mengatakan "Itu tidak akan mengganggu kode lain yang sedang berjalan"; Apakah Anda berbicara tentang kode panggilan balik hanya dalam pernyataan pertama? Tolong beri tahu saya.
krishna

2
Nettuts memiliki tutorial yang cukup bagus dalam menjelaskan dasar-dasar async di sini: net.tutsplus.com/tutorials/javascript-ajax/…
RobW

26
@cletus Pernyataan "Kode akan berhenti dieksekusi sampai panggilan kembali" perlu diperbaiki karena eksekusi tidak berhenti. Eksekusi kode dapat dilanjutkan. Kalau tidak, itu berarti panggilan itu sinkron.
HS.

1
Saya tidak mengerti pernyataan itu juga.
towry

12
Jawaban ini sangat menyesatkan dan membingungkan. Silakan lihat jawaban CMS atau Faraz Ahmad sebagai gantinya.
iono

214

JavaScript adalah utas tunggal dan memiliki model eksekusi yang sinkron. Utas tunggal berarti bahwa satu perintah dijalankan pada satu waktu. Sinkron berarti satu per satu yaitu satu baris kode dieksekusi pada suatu waktu agar kode muncul. Jadi dalam JavaScript satu hal terjadi pada satu waktu.

Konteks Eksekusi

Mesin JavaScript berinteraksi dengan mesin lain di browser. Dalam tumpukan eksekusi JavaScript ada konteks global di bagian bawah dan kemudian ketika kita menjalankan fungsi mesin JavaScript membuat konteks eksekusi baru untuk fungsi masing-masing. Ketika fungsi yang dipanggil keluar dari konteks pelaksanaannya muncul dari tumpukan, dan kemudian konteks eksekusi berikutnya muncul dan seterusnya ...

Sebagai contoh

function abc()
{
   console.log('abc');
}


function xyz()
{
   abc()
   console.log('xyz');
}
var one = 1;
xyz();

Dalam kode di atas konteks eksekusi global akan dibuat dan dalam konteks ini var oneakan disimpan dan nilainya akan menjadi 1 ... ketika doa xyz () dipanggil maka konteks eksekusi baru akan dibuat dan jika kita telah mendefinisikan variabel apa pun dalam fungsi xyz variabel-variabel tersebut akan disimpan dalam konteks eksekusi xyz (). Dalam fungsi xyz kita memanggil abc () dan kemudian konteks eksekusi abc () dibuat dan meletakkan di tumpukan eksekusi ... Sekarang ketika abc () selesai konteksnya muncul dari stack, maka konteks xyz () muncul dari tumpukan dan kemudian konteks global akan muncul ...

Sekarang tentang panggilan balik yang tidak sinkron; asinkron berarti lebih dari satu per satu.

Sama seperti tumpukan eksekusi ada Antrian Acara . Ketika kami ingin diberitahu tentang beberapa peristiwa di mesin JavaScript kami dapat mendengarkan acara itu, dan acara tersebut ditempatkan di antrian. Misalnya acara permintaan Ajax, atau acara permintaan HTTP.

Setiap kali tumpukan eksekusi kosong, seperti yang ditunjukkan dalam contoh kode di atas, mesin JavaScript secara berkala melihat antrian acara dan melihat apakah ada acara yang akan diberitahukan. Misalnya dalam antrian ada dua peristiwa, permintaan ajax dan permintaan HTTP. Itu juga terlihat untuk melihat apakah ada fungsi yang perlu dijalankan pada pemicu acara itu ... Jadi mesin JavaScript diberitahu tentang acara tersebut dan tahu fungsi masing-masing untuk mengeksekusi pada acara itu ... Jadi mesin JavaScript memanggil fungsi handler, dalam contoh kasus, misalnya AjaxHandler () akan dipanggil dan seperti biasa ketika suatu fungsi dipanggil konteks eksekusi ditempatkan pada konteks eksekusi dan sekarang eksekusi fungsi selesai dan permintaan acara ajax juga dihapus dari antrian acara ... Ketika AjaxHandler () menyelesaikan tumpukan eksekusi kosong sehingga mesin kembali melihat antrian acara dan menjalankan fungsi event handler dari permintaan HTTP yang berikutnya dalam antrian. Penting untuk diingat bahwa antrian acara diproses hanya ketika tumpukan eksekusi kosong.

Sebagai contoh, lihat kode di bawah ini menjelaskan tumpukan eksekusi dan penanganan antrian acara oleh mesin Javascript.

function waitfunction() {
    var a = 5000 + new Date().getTime();
    while (new Date() < a){}
    console.log('waitfunction() context will be popped after this line');
}

function clickHandler() {
    console.log('click event handler...');   
}

document.addEventListener('click', clickHandler);


waitfunction(); //a new context for this function is created and placed on the execution stack
console.log('global context will be popped after this line');

Dan

<html>
    <head>

    </head>
    <body>

        <script src="program.js"></script>
    </body>
</html>

Sekarang jalankan halaman web dan klik pada halaman, dan lihat hasilnya di konsol. Outputnya adalah

waitfunction() context will be popped after this line
global context will be emptied after this line
click event handler...

Mesin JavaScript menjalankan kode secara sinkron seperti yang dijelaskan dalam bagian konteks eksekusi, browser secara tidak sinkron menempatkan sesuatu dalam antrian acara. Jadi fungsi yang membutuhkan waktu sangat lama untuk diselesaikan dapat mengganggu penanganan acara. Hal-hal yang terjadi di browser seperti acara ditangani dengan cara ini oleh JavaScript, jika ada pendengar yang seharusnya menjalankan, mesin akan menjalankannya ketika tumpukan eksekusi kosong. Dan peristiwa diproses sesuai urutan kejadiannya, jadi bagian asinkronnya adalah tentang apa yang terjadi di luar mesin, yaitu apa yang harus dilakukan mesin ketika kejadian luar itu terjadi.

Jadi JavaScript selalu sinkron.


16
Jawaban ini sangat jelas, seharusnya mendapatkan lebih banyak upvotes.
ranu

7
Tentu saja penjelasan terbaik untuk perilaku asinkron Javascript yang saya baca.
Charles Jaimet

1
Penjelasan yang bagus tentang konteks eksekusi dan antrian.
Divyanshu Maithani

1
Tentu saja ini mengharuskan Anda membaca sedikit tentang tumpukan konteks eksekusi, dan hanya penambahan itu menjadi kosong dan acara que membuat saya akhirnya merasa seperti saya mengerti pengecualian skrip java secara deterministik. Yang lebih buruk adalah saya merasa hanya membutuhkan satu halaman membaca namun saya merasa sulit menemukannya di mana pun. Jadi mengapa tidak ada yang mengatakannya begitu saja? Entah mereka tidak tahu atau apa? Tapi saya merasa jika tutorial js punya ini bisa menyelamatkan saya banyak waktu. >: |
kerajinan Marshal

2
Penjelasan sempurna!
Julsy

100

JavaScript adalah single-threaded, dan sepanjang waktu Anda bekerja pada eksekusi alur-kode yang normal.

Contoh bagus dari perilaku asinkron yang dimiliki oleh JavaScript adalah peristiwa (interaksi pengguna, hasil permintaan Ajax, dll) dan timer, pada dasarnya tindakan yang mungkin terjadi kapan saja.

Saya akan merekomendasikan Anda untuk melihat artikel berikut:

Artikel itu akan membantu Anda untuk memahami sifat single-threaded dari JavaScript dan bagaimana timer bekerja secara internal dan bagaimana eksekusi JavaScript asinkron bekerja.

async


Jawaban yang diterima menyesatkan, bisakah kita melakukan sesuatu dalam kasus itu? /
Suraj Jain

8

Bagi seseorang yang benar-benar memahami cara kerja JS, pertanyaan ini mungkin kelihatan tidak menyenangkan, namun kebanyakan orang yang menggunakan JS tidak memiliki tingkat wawasan yang begitu dalam (dan tidak perlu membutuhkannya) dan bagi mereka ini adalah titik yang cukup membingungkan, saya akan coba jawab dari perspektif itu.

JS sinkron dalam hal kode dijalankan. setiap baris hanya berjalan setelah baris sebelum selesai dan jika jalur itu memanggil fungsi setelah selesai, dll ...

Titik utama kebingungan muncul dari kenyataan bahwa browser Anda dapat memberitahu JS untuk mengeluarkan lebih banyak kode kapan saja (simmlar bagaimana Anda dapat mengeluarkan lebih banyak kode JS pada halaman dari konsol). Sebagai contoh JS memiliki fungsi-fungsi Callback yang tujuannya adalah untuk memungkinkan JS untuk MEMILIKI secara asinkron sehingga bagian-bagian selanjutnya dari JS dapat berjalan sambil menunggu fungsi JS yang telah dieksekusi (yaitu GETpanggilan) untuk mengembalikan kembali sebuah jawaban, JS akan terus berjalan hingga browser memiliki jawaban pada saat itu loop acara (browser) akan menjalankan kode JS yang memanggil fungsi panggilan balik.

Karena loop peristiwa (browser) dapat memasukkan lebih banyak JS yang akan dieksekusi pada titik mana pun dalam arti JS adalah asinkron (hal-hal utama yang akan menyebabkan browser memasukkan kode JS adalah batas waktu, panggilan balik dan peristiwa)

Saya harap ini cukup jelas untuk membantu seseorang.


4

Definisi

Istilah "asinkron" dapat digunakan dalam arti yang sedikit berbeda, menghasilkan jawaban yang tampaknya bertentangan di sini, sedangkan sebenarnya tidak. Wikipedia di Asynchrony memiliki definisi ini:

Asynchrony, dalam pemrograman komputer, mengacu pada terjadinya peristiwa yang tidak tergantung pada alur program utama dan cara untuk menangani peristiwa tersebut. Ini bisa berupa peristiwa "di luar" seperti kedatangan sinyal, atau tindakan yang dipicu oleh program yang terjadi bersamaan dengan eksekusi program, tanpa pemblokiran program untuk menunggu hasil.

kode non-JavaScript dapat mengantri acara "luar" seperti itu ke beberapa antrean acara JavaScript. Tapi sejauh itulah yang terjadi.

Tanpa Preemption

Tidak ada gangguan eksternal dalam menjalankan kode JavaScript untuk mengeksekusi beberapa kode JavaScript lain dalam skrip Anda. Potongan-potongan JavaScript dieksekusi satu demi satu, dan urutannya ditentukan oleh urutan peristiwa di setiap antrian acara, dan prioritas antrian tersebut.

Misalnya, Anda dapat benar-benar yakin bahwa tidak ada JavaScript lain (dalam skrip yang sama) yang akan pernah dijalankan ketika bagian kode berikut dijalankan:

let a = [1, 4, 15, 7, 2];
let sum = 0;
for (let i = 0; i < a.length; i++) {
    sum += a[i];
}

Dengan kata lain, tidak ada preemption dalam JavaScript. Apa pun yang mungkin ada dalam antrian acara, pemrosesan acara tersebut harus menunggu sampai potongan kode tersebut selesai. Spesifikasi EcmaScript mengatakan di bagian 8.4 Pekerjaan dan Antrian Pekerjaan :

Eksekusi suatu Pekerjaan dapat dimulai hanya ketika tidak ada konteks eksekusi yang berjalan dan tumpukan konteks eksekusi kosong.

Contoh Asynchrony

Seperti yang sudah ditulis orang lain, ada beberapa situasi di mana asynchrony berperan dalam JavaScript, dan selalu melibatkan antrian acara, yang hanya dapat menghasilkan eksekusi JavaScript ketika tidak ada eksekusi kode JavaScript lainnya:

  • setTimeout(): agen (mis. peramban) akan menempatkan acara dalam antrian acara ketika batas waktu telah kedaluwarsa. Pemantauan waktu dan penempatan acara dalam antrian terjadi oleh kode non-JavaScript, sehingga Anda dapat membayangkan ini terjadi secara paralel dengan potensi eksekusi beberapa kode JavaScript. Tetapi panggilan balik yang disediakan setTimeouthanya dapat mengeksekusi ketika kode JavaScript yang saat ini dijalankan telah selesai dan antrian acara yang sesuai sedang dibaca.

  • fetch(): agen akan menggunakan fungsi OS untuk melakukan permintaan HTTP dan memonitor respons yang masuk. Sekali lagi, tugas non-JavaScript ini dapat berjalan secara paralel dengan beberapa kode JavaScript yang masih dieksekusi. Tetapi prosedur resolusi janji, yang akan menyelesaikan janji yang dikembalikan oleh fetch(), hanya dapat dijalankan ketika JavaScript yang sedang dijalankan telah selesai.

  • requestAnimationFrame(): mesin rendering browser (non-JavaScript) akan menempatkan suatu peristiwa dalam antrian JavaScript saat mesin siap untuk melakukan operasi pengecatan. Ketika acara JavaScript diproses, fungsi panggilan balik dijalankan.

  • queueMicrotask(): segera menempatkan acara di antrian mikrotask. Callback akan dieksekusi ketika tumpukan panggilan kosong dan peristiwa itu dikonsumsi.

Ada banyak contoh lagi, tetapi semua fungsi ini disediakan oleh lingkungan host, bukan oleh inti EcmaScript. Dengan inti EcmaScript Anda serempak dapat menempatkan sebuah acara di sebuah Janji Kerja Antrian dengan Promise.resolve().

Konstruksi Bahasa

EcmaScript menyediakan beberapa bahasa konstruksi untuk mendukung pola asynchrony, seperti yield, async, await. Tetapi jangan ada kesalahan: kode JavaScript tidak akan terganggu oleh peristiwa eksternal. The "interupsi" yang yielddan awaittampaknya memberikan hanyalah cara yang terkendali dan telah ditentukan untuk kembali dari panggilan fungsi dan mengembalikan konteks eksekusi nanti, baik dengan kode JS (dalam kasus yield), atau antrian acara (dalam kasus await).

Penanganan acara DOM

Ketika kode JavaScript mengakses DOM API, ini dalam beberapa kasus dapat membuat DOM API memicu satu atau lebih pemberitahuan sinkron. Dan jika kode Anda memiliki pengendali acara mendengarkan itu, itu akan dipanggil.

Ini mungkin dianggap sebagai konkurensi pre-emptive, tetapi ini bukan: begitu event handler Anda kembali, API DOM akhirnya juga akan kembali, dan kode JavaScript asli akan berlanjut.

Dalam kasus lain, DOM API hanya akan mengirimkan acara dalam antrian acara yang sesuai, dan JavaScript akan mengambilnya setelah tumpukan panggilan dikosongkan.

Lihat acara sinkron dan asinkron


0

Sinkron dalam semua kasus.

Contoh pemblokiran utas dengan Promises:

  const test = () => new Promise((result, reject) => {
    const time = new Date().getTime() + (3 * 1000);

    console.info('Test start...');

    while (new Date().getTime() < time) {
      // Waiting...
    }

    console.info('Test finish...');
  });

  test()
    .then(() => console.info('Then'))
    .finally(() => console.info('Finally'));

  console.info('Finish!');

Outputnya adalah:

Test start...
Test finish...
Finish!
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.