let x = 0;
async function test() {
x += await 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Nilai-nilai yang x
dicatat adalah 1
dan 5
. Pertanyaan saya adalah: mengapa nilai x
5
pada log kedua?
Jika test
dieksekusi setelah x += 1
(karena ini adalah fungsi async) maka nilai x adalah 1 pada saat test
dieksekusi, jadi x += await 5
harus membuat nilai x
6
.
javascript
async-await
event-loop
ALDRIN P VINCENT
sumber
sumber
await (x += 5)
danx += await 5
.Jawaban:
TL; DR: Karena
+=
membacax
sebelumnya, tetapi menulisnya setelah itu berubah, karenaawait
kata kunci dalam operan kedua (sisi kanan).async
fungsi berjalan secara sinkron ketika mereka dipanggil hinggaawait
pernyataan pertama .Jadi, jika Anda menghapus
await
, berperilaku seperti fungsi normal (dengan pengecualian bahwa itu masih mengembalikan Janji).Jika demikian, Anda masuk
5
dan6
masuk ke konsol:Yang pertama
await
berhenti berjalan secara sinkron, meskipun argumennya tersedia secara sinkron, sehingga yang berikut akan kembali1
dan6
, seperti yang Anda harapkan:Namun, kasing Anda sedikit lebih rumit.
Anda telah memasukkan
await
ekspresi yang digunakan+=
.Anda mungkin tahu, bahwa di JS
x += y
identik denganx = (x + y)
. Saya akan menggunakan formulir yang terakhir untuk pemahaman yang lebih baik:Ketika penerjemah mencapai garis ini ...
... mulai mengevaluasinya, dan ternyata menjadi ...
... lalu, ia mencapai
await
dan berhenti.Kode setelah panggilan fungsi mulai berjalan, dan mengubah nilai
x
, lalu mencatatnya.x
sekarang1
.Kemudian, setelah skrip utama keluar, interpreter kembali ke
test
fungsi yang dijeda , dan terus mengevaluasi baris itu:Dan, karena nilai
x
sudah diganti, itu tetap0
.Akhirnya, penafsir melakukan penambahan, toko
5
untukx
, dan log itu.Anda dapat memeriksa perilaku ini dengan masuk ke dalam pengambil / penyetel properti objek (dalam contoh ini,
y.z
mencerminkan nilai darix
:sumber
x += y
identik denganx = (x + y)
." - Ini bukan kasus dalam setiap situasi dalam setiap bahasa, tetapi secara umum Anda dapat mengandalkan mereka bertindak sama.Pernyataan Anda
x += await 5
berkeinginan untukNilai
_temp
orary adalah0
, dan jika Anda berubahx
selamaawait
(yang kode Anda lakukan) itu tidak masalah, itu akan diberikan5
setelahnya.sumber
Kode ini cukup rumit untuk diikuti karena dibutuhkan beberapa lompatan async yang tak terduga. Mari kita periksa (dekat) bagaimana itu sebenarnya akan dieksekusi dan saya akan menjelaskan mengapa setelah itu. Saya juga mengubah log konsol untuk menambahkan nomor - membuatnya lebih mudah merujuk dan juga menunjukkan apa yang dicatat:
Jadi, kode itu tidak benar-benar berjalan lurus, itu sudah pasti. Dan kami juga memiliki
4/7
hal yang aneh . Dan itu benar-benar keseluruhan masalah di sini.Pertama-tama, mari kita perjelas - fungsi async sebenarnya tidak sepenuhnya asinkron. Mereka hanya akan menghentikan eksekusi dan melanjutkan nanti jika
await
kata kunci digunakan. Tanpa itu, mereka mengeksekusi dari atas ke bawah, ekspresi demi ekspresi secara serempak:Jadi, hal pertama yang perlu kita ketahui bahwa menggunakan
await
akan membuat sisa fungsi dieksekusi nanti. Dalam contoh yang diberikan, itu berarti bahwaconsole.log('x1 :', x)
akan dieksekusi setelah sisa kode sinkron. Itu karena setiap Janji akan diselesaikan setelah loop acara saat ini selesai.Jadi, ini menjelaskan mengapa kita
x2 : 1
login terlebih dahulu dan mengapax2 : 5
login kedua tetapi tidak mengapa nilai terakhir5
. Secara logisx += await 5
seharusnya5
... tetapi di sini adalah tangkapan kedua untukawait
kata kunci - itu akan menghentikan sementara pelaksanaan fungsi tetapi apa pun sebelum sudah berjalan.x += await 5
sebenarnya akan diproses dengan cara berikutx
. Pada saat eksekusi, itu0
.await
ungkapan selanjutnya yaitu5
. Jadi, fungsinya berhenti sekarang dan akan dilanjutkan lagi nanti.0 + 5
x
Jadi, jeda fungsi setelah membaca bahwa
x
adalah0
dan dilanjutkan bila itu sudah berubah, bagaimanapun, tidak membaca kembali nilaix
.Jika kita membuka bungkusan tersebut
await
ke dalamPromise
setara yang akan mengeksekusi, Anda harus:sumber
Ya itu sedikit rumit apa yang sebenarnya terjadi adalah kedua operasi penambahan terjadi parellaly sehingga operasi akan seperti:
Dalam janji:
x += await 5
==>x = x + await 5
==>x = 0 + await 5
==>5
Di luar:
x += 1
==>x = x + 1
==>x = 0 + 1
==>1
karena semua operasi di atas terjadi dari kiri ke kanan, bagian pertama dari penambahan dapat dihitung pada waktu yang sama dan karena ada menunggu sebelum 5 yang additio dapat menunda sedikit. Anda dapat melihat eksekusi dengan meletakkan breakpoint di dalam kode.
sumber
Async dan Await adalah perpanjangan dari janji. Fungsi async dapat berisi ekspresi menunggu yang menjeda eksekusi fungsi async dan menunggu resolusi Promise yang disahkan, dan kemudian melanjutkan eksekusi fungsi async dan mengembalikan nilai yang diselesaikan. Ingat, kata kunci yang menunggu hanya valid di dalam fungsi async.
Bahkan jika Anda telah mengubah nilai x setelah memanggil fungsi tes, masih nilai x akan tetap 0 karena fungsi async telah dibuat itu contoh baru. Berarti semuanya berubah pada variabel di luarnya tidak akan mengubah nilai di dalamnya setelah dipanggil. Kecuali jika Anda menempatkan kenaikan Anda di atas fungsi tes.
sumber
let x="Didn't receive change"; (async()=>{await 'Nothing'; console.log(x); await new Promise(resolve=>setTimeout(resolve,2000)); console.log(x)})(); x='Received synchronous change'; setTimeout(()=>{x='Received change'},1000)
Ini outputReceived synchronous change
danReceived change