console.log () async atau sync?

93

Saya sedang membaca Async Javascript oleh Trevor Burnham. Sejauh ini, ini adalah buku yang bagus.

Dia berbicara tentang cuplikan dan console.log ini menjadi 'asinkron' di konsol Safari dan Chrome. Sayangnya saya tidak bisa meniru ini. Ini kodenya:

var obj = {}; 
console.log(obj); 
obj.foo = 'bar';
// my outcome: Object{}; 'bar';
// The book outcome: {foo:bar};

Jika ini asinkron, saya akan mengantisipasi hasilnya adalah hasil buku. console.log () diletakkan di antrian event sampai semua kode dijalankan, lalu dijalankan dan akan memiliki properti bar.

Tampaknya itu berjalan serempak.

Apakah saya menjalankan kode ini salah? Apakah console.log sebenarnya async?

Halo Dunia
sumber
@thefourtheye: Tidak, jadi sebaiknya saya menghapus komentar saya.
monster kue
1
Saya telah melihat itu terjadi di Chrome. Jika Anda console.log objek sederhana dan kemudian segera mengubah sesuatu di objek, console.log()itu tidak selalu menampilkan nilai sebelumnya. Solusi jika ini terjadi pada Anda adalah mengubah apa pun yang Anda coba console.log()menjadi string yang tidak dapat diubah sehingga tidak tunduk pada masalah ini. Jadi, dari pengalaman console.log()memiliki beberapa masalah asinkron yang mungkin terkait dengan data marsaling melintasi batas proses. Ini bukan perilaku yang dimaksudkan, tetapi beberapa efek samping dari cara console.log()kerjanya secara internal (saya pribadi menganggapnya sebagai bug).
jfriend00
1
@bergi hanya butuh waktu 10 menit untuk menemukan penipuan ini (walaupun saya tahu nama persisnya), mungkin karena dupeclosed. Tidak bisakah kita menukar duplikatnya, sehingga yang lain akan menjadi korban penipuan ...?
Jonas Wilms
1
@JonasWilms Sekarang saya telah membuka kembali pertanyaan ini (lihat riwayat ). Saya tidak berpikir mereka duplikat satu sama lain, saya menggunakan Apakah konsol JavaScript Chrome malas mengevaluasi array? sebagai target kanonik untuk masalah yang secara khusus melibatkan larik.
Bergi

Jawaban:

114

console.logtidak terstandarisasi, sehingga perilakunya agak tidak ditentukan, dan dapat diubah dengan mudah dari rilis ke rilis alat pengembang. Buku Anda sepertinya sudah ketinggalan zaman, begitu juga jawaban saya segera.

Untuk kode kami, tidak ada bedanya apakah console.logasync atau tidak, tidak menyediakan jenis panggilan balik atau lebih; dan nilai yang Anda berikan selalu direferensikan dan dihitung pada saat Anda memanggil fungsi tersebut.

Kami tidak benar-benar tahu apa yang terjadi kemudian (OK, kami bisa, karena Firebug, Chrome Devtools dan Opera Dragonfly semuanya open source). Konsol perlu menyimpan nilai yang dicatat di suatu tempat, dan itu akan menampilkannya di layar. Rendering pasti akan terjadi secara asinkron (dibatasi hingga pembaruan batas kecepatan), begitu pula interaksi di masa mendatang dengan objek yang dicatat di konsol (seperti memperluas properti objek).

Jadi konsol mungkin akan mengkloning (membuat serial) objek yang bisa berubah yang Anda catat, atau akan menyimpan referensi ke sana. Yang pertama tidak berfungsi dengan baik dengan objek dalam / besar. Juga, setidaknya rendering awal di konsol mungkin akan menunjukkan status "saat ini" dari objek, yaitu saat ia masuk - dalam contoh Anda, Anda lihat Object {}.

Namun, saat Anda memperluas objek untuk memeriksa propertinya lebih jauh, kemungkinan konsol hanya akan menyimpan referensi ke objek dan propertinya, dan menampilkannya sekarang akan menampilkan status saat ini (sudah bermutasi). Jika Anda mengklik +, Anda akan melihat barproperti dalam contoh Anda.

Berikut adalah tangkapan layar yang telah diposting di laporan bug untuk menjelaskan "perbaikan" mereka:

Jadi, beberapa nilai mungkin direferensikan lama setelah dicatat, dan evaluasinya agak lambat ("bila diperlukan"). Contoh paling terkenal dari perbedaan ini ditangani dalam pertanyaan Apakah konsol JavaScript Chrome malas mengevaluasi array?

Solusinya adalah memastikan untuk selalu mencatat snapshot serial dari objek Anda, misalnya dengan melakukan console.log(JSON.stringify(obj)). Ini akan bekerja untuk objek non-lingkaran dan agak kecil saja. Lihat juga Bagaimana cara mengubah perilaku default console.log di Safari? .

Solusi yang lebih baik adalah dengan menggunakan breakpoint untuk debugging, di mana eksekusi benar-benar berhenti dan Anda dapat memeriksa nilai saat ini di setiap titik. Gunakan logging hanya dengan data yang dapat diserialisasikan dan tidak dapat diubah.

Bergi
sumber
2
Saya memiliki masalah yang sama dengan console.log yang tidak async. menggunakan JSON.stringify memperbaikinya untuk saya
russiansummer
Pada 2019, dapatkah kita mengatakan bahwa console.logmasih asinkron di Chrome seperti yang berumur 8 tahun (lihat stackoverflow.com/questions/7389069/… ), satu-satunya hal yang berubah adalah bahwa sekarang Chrome mengeluarkan cuplikan dari objek referensi di kali Anda memanggil console.log(jika Anda memperluas objek yang dicatat, Anda akan melihat properti dan nilai akhirnya setelah operasi mutasi yang Anda lakukan setelahnya console.log), atau console.logmemang sinkron?
tonix
@tonix Ya, perilaku ini sepertinya tidak akan diubah karena alasan yang dijelaskan dalam jawaban saya. Ini bukan bug, ini hanya cara kerja debugger / inspektur interaktif.
Bergi
Jika Anda menggunakan JSON.parse(JSON.stringify(obj))seperti yang juga disebutkan dalam komentar di sini Anda mendapatkan snapshot dalam bentuk objek, bukan string.
Layu
TL; DR. Jalan jalan TL
Rick O'Shea
2

Ini sebenarnya bukan jawaban untuk pertanyaan, tetapi mungkin berguna bagi seseorang yang tersandung pada posting ini, dan itu terlalu panjang untuk memberikan komentar:

window.console.logSync = (...args) => {
  try {
    args = args.map((arg) => JSON.parse(JSON.stringify(arg)));
    console.log(...args);
  } catch (error) {
    console.log('Error trying to console.logSync()', ...args);
  }
};

Ini membuat versi pseudo-sinkronis console.log, tetapi dengan peringatan yang sama seperti yang disebutkan dalam jawaban yang diterima.

Karena sepertinya, saat ini, sebagian besar browser console.logtidak sinkron dalam beberapa hal, Anda mungkin ingin menggunakan fungsi seperti ini dalam skenario tertentu.

V. Rubinetti
sumber
0

Saat menggunakan console.log:

a = {}; a.a=1;console.log(a);a.b=function(){};
// without b
a = {}; a.a=1;a.a1=1;a.a2=1;a.a3=1;a.a4=1;a.a5=1;a.a6=1;a.a7=1;a.a8=1;console.log(a);a.b=function(){};
// with b, maybe
a = {}; a.a=function(){};console.log(a);a.b=function(){};
// with b

dalam situasi pertama, objek cukup sederhana, sehingga konsol dapat 'merangkai' objek tersebut kemudian ditampilkan kepada Anda; tetapi dalam situasi lain, a terlalu 'rumit' untuk 'dirangkai' sehingga konsol akan menampilkan objek dalam memori sebagai gantinya, dan ya, ketika Anda melihatnya b telah dilampirkan ke a.

Miao Siyu
sumber
Saya tahu pertanyaan ini berumur 3 tahun tetapi sekarang saya menjalankan masalah yang sama - membuat serialisasi objek tidak berhasil untuk saya karena terlalu rumit. Saya menangkap acara mencoba mengakses datanya tetapi entah bagaimana itu tidak memiliki data dalam kode tetapi di console.log memiliki data.
Skeec