console.log () asynchron oder synchron?

93

Ich lese gerade Async Javascript von Trevor Burnham. Dies war bisher ein großartiges Buch.

Er spricht davon, dass dieses Snippet und console.log in der Safari- und Chrome-Konsole "asynchron" sind. Leider kann ich das nicht replizieren. Hier ist der Code:

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

Wenn dies asynchron wäre, würde ich davon ausgehen, dass das Ergebnis das Buchergebnis ist. console.log () wird in die Ereigniswarteschlange gestellt, bis der gesamte Code ausgeführt wird. Anschließend wird es ausgeführt und verfügt über die Eigenschaft bar.

Es wird angezeigt, obwohl es synchron ausgeführt wird.

Führe ich diesen Code falsch aus? Ist console.log tatsächlich asynchron?

Hallo Welt
quelle
@thefourtheye: Nein, also sollte ich wahrscheinlich einfach meinen Kommentar löschen.
Keks Monster
1
Ich habe es in Chrome gesehen. Wenn Sie ein einfaches Objekt console.log und dann sofort etwas im Objekt ändern, console.log()zeigt das nicht immer den vorherigen Wert an. Die Umgehung, wenn Ihnen dies passiert, besteht darin, alles, was Sie versuchen, console.log()in eine Zeichenfolge zu konvertieren, die unveränderlich ist, sodass dieses Problem nicht auftritt. Aus Erfahrung console.log()gibt es also einige asynchrone Probleme, die wahrscheinlich mit dem Sammeln von Daten über Prozessgrenzen hinweg zusammenhängen. Dies ist nicht das beabsichtigte Verhalten, sondern ein Nebeneffekt der console.log()internen Funktionsweise (ich persönlich würde es als Fehler betrachten).
jfriend00
1
@bergi Ich habe nur 10 Minuten gebraucht, um diesen Betrüger zu finden (obwohl ich den genauen Namen kannte), wahrscheinlich weil er nicht abgeschlossen ist. Könnten wir nicht einfach das Duplikat tauschen, damit das andere der Betrüger ist ...?
Jonas Wilms
1
@ JonasWilms Ich habe diese Frage jetzt wieder geöffnet (siehe Geschichte ). Ich glaube nicht, dass sie Duplikate voneinander sind. Ich verwende Ist die JavaScript-Konsole von Chrome faul bei der Bewertung von Arrays? als kanonisches Ziel für Probleme, die speziell ein Array betreffen.
Bergi

Antworten:

112

console.logist nicht standardisiert, daher ist das Verhalten eher undefiniert und kann leicht von Release zu Release der Entwicklertools geändert werden. Ihr Buch ist wahrscheinlich veraltet, ebenso wie meine baldige Antwort.

Für unseren Code macht es keinen Unterschied, ob er console.logasynchron ist oder nicht, er bietet keinerlei Rückruf oder so; und die Werte, die Sie übergeben, werden immer zum Zeitpunkt des Aufrufs der Funktion referenziert und berechnet.

Wir wissen nicht wirklich, was dann passiert (OK, wir könnten, da Firebug, Chrome Devtools und Opera Dragonfly alle Open Source sind). Die Konsole muss die protokollierten Werte irgendwo speichern und zeigt sie auf dem Bildschirm an. Das Rendern wird mit Sicherheit asynchron erfolgen (gedrosselt, um Aktualisierungen mit Ratenbegrenzung durchzuführen), ebenso wie zukünftige Interaktionen mit den protokollierten Objekten in der Konsole (wie das Erweitern von Objekteigenschaften).

Die Konsole kann also entweder die veränderlichen Objekte, die Sie protokolliert haben, klonen (serialisieren) oder Verweise darauf speichern. Der erste funktioniert nicht gut mit tiefen / großen Objekten. Zumindest beim ersten Rendern in der Konsole wird wahrscheinlich der "aktuelle" Status des Objekts angezeigt, dh der, als es protokolliert wurde - in Ihrem Beispiel sehen Sie Object {}.

Wenn Sie das Objekt jedoch erweitern, um seine Eigenschaften weiter zu untersuchen, hat die Konsole wahrscheinlich nur einen Verweis auf Ihr Objekt und seine Eigenschaften gespeichert. Wenn Sie diese jetzt anzeigen, wird der aktuelle (bereits mutierte) Status angezeigt. Wenn Sie auf klicken +, sollte die barEigenschaft in Ihrem Beispiel angezeigt werden.

Hier ist ein Screenshot, der im Fehlerbericht veröffentlicht wurde , um deren "Fix" zu erklären:

Daher werden einige Werte möglicherweise lange nach der Protokollierung referenziert, und die Auswertung dieser Werte ist eher träge ("bei Bedarf"). Das bekannteste Beispiel für diese Diskrepanz ist die Frage, ob die JavaScript-Konsole von Chrome bei der Bewertung von Arrays faul ist.

Eine Problemumgehung besteht darin, sicherzustellen, dass serialisierte Snapshots Ihrer Objekte immer protokolliert werden, z console.log(JSON.stringify(obj)). Dies funktioniert jedoch nur für nicht kreisförmige und eher kleine Objekte. Siehe auch Wie kann ich das Standardverhalten von console.log in Safari ändern? .

Die bessere Lösung besteht darin, Haltepunkte für das Debuggen zu verwenden, bei denen die Ausführung vollständig gestoppt wird und Sie die aktuellen Werte an jedem Punkt überprüfen können. Verwenden Sie die Protokollierung nur mit serialisierbaren und unveränderlichen Daten.

Bergi
quelle
2
Ich hatte das gleiche Problem mit console.log nicht asynchron. mit JSON.stringify es für mich festgelegt
russiansummer
Können wir ab 2019 sagen, dass dies console.login Chrome immer noch asynchron ist, da es 8 Jahre alt war (siehe stackoverflow.com/questions/7389069/… ). Das einzige, was sich ändert, ist, dass Chrome jetzt eine Momentaufnahme des Referenzobjekts am ausgibt console.logWenn Sie aufrufen (wenn Sie das protokollierte Objekt erweitern, werden seine endgültigen Eigenschaften und Werte nach den Mutationsoperationen angezeigt, nach denen Sie ausgeführt haben console.log) oder ist es console.logtatsächlich synchron?
Tonix
@tonix Ja, es ist unwahrscheinlich, dass sich dieses Verhalten aufgrund der in meiner Antwort genannten Gründe ändert. Es ist kein Fehler, sondern nur die Funktionsweise eines interaktiven Debuggers / Inspektors.
Bergi
Wenn Sie JSON.parse(JSON.stringify(obj))wie im Kommentar hier erwähnt verwenden, erhalten Sie anstelle einer Zeichenfolge einen Schnappschuss in Objektform.
Wilt
TL; DR.way way way TL
Rick O'Shea
2

Dies ist keine wirkliche Antwort auf die Frage, aber es könnte für jemanden nützlich sein, der über diesen Beitrag gestolpert ist, und es war zu lang, um einen Kommentar abzugeben:

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

Dies erzeugt eine pseudosynchrone Version von console.log, jedoch mit den gleichen Einschränkungen wie in der akzeptierten Antwort erwähnt.

Da es derzeit so aussieht, als ob die meisten Browser console.login irgendeiner Weise asynchron sind, möchten Sie in bestimmten Szenarien möglicherweise eine solche Funktion verwenden.

V. Rubinetti
quelle
0

Bei Verwendung von 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

In der ersten Situation ist das Objekt einfach genug, sodass die Konsole es "stringifizieren" und dann für Sie präsentieren kann. In anderen Situationen ist a jedoch zu "kompliziert", um es zu "stringifizieren", sodass die Konsole stattdessen das In-Memory-Objekt anzeigt. Ja, wenn Sie es betrachten, ist b bereits an a angehängt.

Miao Siyu
quelle
Ich weiß, dass diese Frage 3 Jahre alt ist, aber im Moment habe ich das gleiche Problem - die Serialisierung des Objekts funktioniert bei mir nicht, weil es zu kompliziert ist. Ich fange ein Ereignis ab, das versucht, auf seine Daten zuzugreifen, aber irgendwie enthält es keine Daten im Code, aber in console.log enthält es Daten.
Skeec