console.log () async czy sync?

93

Obecnie czytam Async Javascript Trevora Burnhama. Jak dotąd to była świetna książka.

Mówi o tym, że ten fragment kodu i console.log są „asynchroniczne” w konsoli Safari i Chrome. Niestety nie mogę tego powtórzyć. Oto kod:

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

Gdyby to było asynchroniczne, spodziewałbym się, że wynik będzie wynikiem książek. console.log () jest umieszczana w kolejce zdarzeń do momentu wykonania całego kodu, a następnie jest uruchamiana i miałby właściwość bar.

Wygląda na to, że działa synchronicznie.

Czy uruchamiam ten kod źle? Czy console.log faktycznie jest asynchroniczna?

Witaj świecie
źródło
@thefourtheye: Nie, więc prawdopodobnie powinienem po prostu usunąć swój komentarz.
cookie monster
1
Widziałem to w Chrome. Jeśli wyślesz prosty obiekt console.log, a następnie natychmiast zmienisz coś w obiekcie, console.log()to nie zawsze pokazuje poprzednią wartość. Rozwiązaniem, jeśli tak się stanie, jest przekonwertowanie wszystkiego, co próbujesz, na console.log()ciąg, który jest niezmienny, więc nie podlega temu problemowi. Tak więc z doświadczenia console.log()wynika, że ​​istnieją pewne problemy z asynchronizacją, prawdopodobnie związane z organizowaniem danych przez granice procesów. Nie jest to zamierzone zachowanie, ale jest efektem ubocznym tego, jak console.log()działa wewnętrznie (osobiście uważam to za błąd).
jfriend00
1
@bergi zajęło mi tylko 10 minut, aby znaleźć ten duplikat (chociaż znałem dokładną nazwę), prawdopodobnie dlatego, że jest podwójnie zamknięty. Czy nie moglibyśmy po prostu zamienić duplikatu, aby ten drugi był oszustem ...?
Jonas Wilms,
1
@JonasWilms Teraz ponownie otworzyłem to pytanie (zobacz historię ). Nie sądzę, że są one swoimi duplikatami. Używam. Czy konsola JavaScript Chrome jest leniwa w ocenie tablic? jako kanoniczny cel dla problemów szczególnie dotyczących macierzy.
Bergi,

Odpowiedzi:

114

console.lognie jest znormalizowany, więc zachowanie jest raczej niezdefiniowane i można je łatwo zmienić od wydania do wydania narzędzi programistycznych. Twoja książka prawdopodobnie jest nieaktualna, podobnie jak moja odpowiedź wkrótce.

W naszym kodzie nie ma znaczenia, czy console.logjest on asynchroniczny, czy nie, nie zapewnia żadnego rodzaju wywołania zwrotnego; a przekazane wartości są zawsze przywoływane i obliczane w momencie wywołania funkcji.

Tak naprawdę nie wiemy, co się wtedy stanie (OK, moglibyśmy, ponieważ Firebug, Chrome Devtools i Opera Dragonfly są open source). Konsola będzie musiała gdzieś przechowywać zarejestrowane wartości i wyświetli je na ekranie. Renderowanie będzie na pewno przebiegać asynchronicznie (ograniczane do aktualizacji limitów szybkości), podobnie jak przyszłe interakcje z zarejestrowanymi obiektami w konsoli (np. Rozwijanie właściwości obiektu).

Konsola może więc albo sklonować (serializować) zmienne obiekty, które zarejestrowałeś, albo będzie przechowywać do nich odniesienia. Pierwsza nie działa dobrze z głębokimi / dużymi obiektami. Ponadto przynajmniej początkowe renderowanie w konsoli prawdopodobnie pokaże „bieżący” stan obiektu, tj. Ten, w którym został zalogowany - w Twoim przykładzie widać Object {}.

Jednak po rozwinięciu obiektu w celu dokładniejszego zbadania jego właściwości jest prawdopodobne, że konsola będzie przechowywać tylko odniesienie do obiektu i jego właściwości, a wyświetlenie ich teraz pokaże ich bieżący (już zmutowany) stan. Jeśli klikniesz na +, powinieneś być w stanie zobaczyć barnieruchomość w swoim przykładzie.

Oto zrzut ekranu, który został opublikowany w raporcie o błędzie, aby wyjaśnić ich „naprawę”:

Tak więc do niektórych wartości można się odwoływać długo po ich zarejestrowaniu, a ich ocena jest raczej leniwa („w razie potrzeby”). Najbardziej znanym przykładem tej rozbieżności jest pytanie Czy konsola JavaScript Chrome jest leniwa w obliczaniu tablic?

Sposób obejścia problemu polega na tym, aby zawsze rejestrować zserializowane migawki obiektów, np. Przez wykonanie console.log(JSON.stringify(obj)) . To zadziała jednak tylko dla nieokrągłych i raczej małych obiektów. Zobacz także Jak mogę zmienić domyślne zachowanie console.log w przeglądarce Safari? .

Lepszym rozwiązaniem jest użycie punktów przerwania do debugowania, w których wykonywanie całkowicie zatrzymuje się i można sprawdzić bieżące wartości w każdym punkcie. Używaj rejestrowania tylko z danymi seryjnymi i niezmiennymi.

Bergi
źródło
2
Miałem ten sam problem, gdy console.log nie była asynchroniczna. używając JSON.stringify naprawiłem to dla mnie
russiansummer
Czy od 2019 roku możemy powiedzieć, że console.lognadal jest asynchroniczny w Chrome, ponieważ miał 8 lat (patrz stackoverflow.com/questions/7389069/ ... ), jedyną rzeczą, która się zmienia, jest to, że teraz Chrome wyświetla migawkę obiektu referencyjnego w podczas wywołania console.log(jeśli rozwiniesz zarejestrowany obiekt, zobaczysz jego końcowe właściwości i wartości po operacjach mutacji, które wykonałeś po console.log), czy console.logrzeczywiście jest synchroniczny?
tonix
@tonix Tak, to zachowanie raczej nie ulegnie zmianie z powodów przedstawionych w mojej odpowiedzi. To nie jest błąd, po prostu działa interaktywny debugger / inspektor.
Bergi
Jeśli użyjesz, JSON.parse(JSON.stringify(obj))jak wspomniano w komentarzu tutaj , otrzymasz migawkę w postaci obiektu, zamiast ciągu.
Wilt
TL; DR. Droga droga TL
Rick O'Shea
2

To nie jest tak naprawdę odpowiedź na pytanie, ale może się przydać komuś, kto natknął się na ten post, a komentarz był zbyt długi:

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

Tworzy to pseudosynchroniczną wersję programu console.log, ale z tymi samymi zastrzeżeniami, które zostały wymienione w zaakceptowanej odpowiedzi.

Ponieważ wydaje się, że w tej chwili większość przeglądarek console.logjest w pewien sposób asynchroniczna, możesz chcieć użyć takiej funkcji w pewnych sytuacjach.

V. Rubinetti
źródło
0

Podczas korzystania z 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

w pierwszej sytuacji obiekt jest na tyle prosty, że konsola może go „zdefiniować”, a następnie przedstawić; ale w innych sytuacjach a jest zbyt „skomplikowane”, aby „zdefiniować”, więc konsola pokaże zamiast tego obiekt w pamięci, i tak, kiedy na to spojrzysz, b jest już dołączone do a.

Miao Siyu
źródło
Wiem, że to pytanie ma 3 lata, ale teraz mam ten sam problem - serializacja obiektu nie działa dla mnie, ponieważ jest zbyt skomplikowana. Łapię zdarzenie, próbując uzyskać dostęp do jego danych, ale jakoś nie ma danych w kodzie, ale w console.log ma dane.
Skeec,