console.log () async o sync?

93

Actualmente estoy leyendo Async Javascript de Trevor Burnham. Este ha sido un gran libro hasta ahora.

Habla de que este fragmento y console.log son 'async' en la consola de Safari y Chrome. Desafortunadamente, no puedo replicar esto. Aquí está el código:

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

Si esto fuera asincrónico, anticiparía que el resultado será el resultado de los libros. console.log () se coloca en la cola de eventos hasta que se ejecute todo el código, luego se ejecuta y tendría la propiedad bar.

Parece que se está ejecutando sincrónicamente.

¿Estoy ejecutando mal este código? ¿Console.log es realmente asincrónico?

Hola Mundo
fuente
@thefourtheye: No, probablemente debería borrar mi comentario.
monstruo de las galletas
1
Lo he visto suceder en Chrome. Si console.log un objeto simple e inmediatamente cambia algo en el objeto, console.log()no siempre muestra el valor anterior. La solución si esto le sucede a usted es convertir todo lo que esté intentando console.log()en una cadena que sea inmutable, por lo que no está sujeta a este problema. Por lo tanto, según la experiencia, console.log()tiene algunos problemas de asincronía probablemente relacionados con la clasificación de datos a través de los límites del proceso. Este no es el comportamiento previsto, pero es un efecto secundario de cómo console.log()funciona internamente (personalmente lo consideraría un error).
jfriend00
1
@bergi, solo me tomó 10 minutos encontrar este engañado (aunque sabía el nombre exacto), probablemente porque está doblemente cerrado. ¿No podríamos simplemente intercambiar el duplicado, para que el otro sea el engañado ...?
Jonas Wilms
1
@JonasWilms Ahora he reabierto esta pregunta (ver historial ). No creo que sean duplicados entre sí, yo uso. ¿La consola JavaScript de Chrome es perezosa para evaluar matrices? como el objetivo canónico para problemas que involucran específicamente una matriz.
Bergi

Respuestas:

114

console.logno está estandarizado, por lo que el comportamiento es bastante indefinido y se puede cambiar fácilmente de una versión a otra de las herramientas de desarrollo. Es probable que su libro esté desactualizado, al igual que mi respuesta pronto.

Para nuestro código, no importa si console.loges asíncrono o no, no proporciona ningún tipo de devolución de llamada; y los valores que pasa siempre se referencian y calculan en el momento en que llama a la función.

Realmente no sabemos qué sucede entonces (de acuerdo, podríamos, ya que Firebug, Chrome Devtools y Opera Dragonfly son todos de código abierto). La consola necesitará almacenar los valores registrados en algún lugar y los mostrará en la pantalla. La renderización ocurrirá de forma asincrónica con seguridad (se limitará a actualizaciones de límite de velocidad), al igual que las interacciones futuras con los objetos registrados en la consola (como expandir las propiedades del objeto).

Entonces, la consola podría clonar (serializar) los objetos mutables que registró, o almacenará referencias a ellos. El primero no funciona bien con objetos grandes o profundos. Además, al menos la representación inicial en la consola probablemente mostrará el estado "actual" del objeto, es decir, el que se registró en el ejemplo que ve Object {}.

Sin embargo, cuando expande el objeto para inspeccionar más sus propiedades, es probable que la consola solo haya almacenado una referencia a su objeto y sus propiedades, y mostrarlos ahora mostrará su estado actual (ya mutado). Si hace clic en +, debería poder ver la barpropiedad en su ejemplo.

Aquí hay una captura de pantalla que se publicó en el informe de errores para explicar su "solución":

Por lo tanto, es posible que se haga referencia a algunos valores mucho después de que se hayan registrado, y la evaluación de estos es bastante lenta ("cuando sea necesario"). El ejemplo más famoso de esta discrepancia se maneja en la pregunta ¿La consola JavaScript de Chrome es perezosa para evaluar matrices?

Una solución alternativa es asegurarse de registrar instantáneas serializadas de sus objetos siempre, por ejemplo, haciendo console.log(JSON.stringify(obj)). Sin embargo, esto funcionará solo para objetos no circulares y bastante pequeños. Consulte también ¿Cómo puedo cambiar el comportamiento predeterminado de console.log en Safari? .

La mejor solución es utilizar puntos de interrupción para la depuración, donde la ejecución se detiene por completo y puede inspeccionar los valores actuales en cada punto. Utilice el registro solo con datos seriales e inmutables.

Bergi
fuente
2
Tuve el mismo problema con console.log que no es asincrónico. usando JSON.stringify lo arregló para mí
russiansummer
A partir de 2019, ¿podemos decir que console.logtodavía es asíncrono en Chrome ya que tenía 8 años (consulte stackoverflow.com/questions/7389069/… ), lo único que cambia es que ahora Chrome genera una instantánea del objeto de referencia en el hora a la que llama console.log(si expande el objeto registrado, verá sus propiedades y valores finales después de las operaciones de mutación que realizó después console.log), o es console.logsincrónico
tonix
@tonix Sí, es poco probable que este comportamiento cambie debido a las razones expuestas en mi respuesta. No es un error, es solo cómo funciona un depurador / inspector interactivo.
Bergi
Si usa JSON.parse(JSON.stringify(obj))como también se menciona en el comentario aquí , obtendrá una instantánea en forma de objeto, en lugar de una cadena.
March
TL; DR.way way way TL
Rick O'Shea
2

Esta no es realmente una respuesta a la pregunta, pero podría ser útil para alguien que tropezó con esta publicación y fue demasiado largo para poner un comentario:

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

Esto crea una versión pseudo-sincrónica de console.log, pero con las mismas advertencias que se mencionan en la respuesta aceptada.

Como parece que, en este momento, la mayoría de los navegadores console.logson asincrónicos de alguna manera, es posible que desee utilizar una función como esta en ciertos escenarios.

V. Rubinetti
fuente
0

Al usar 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

en la primera situación, el objeto es lo suficientemente simple, por lo que la consola puede 'encadenarlo' y luego presentárselo; pero en las otras situaciones, a es demasiado 'complicado' para 'encadenar', por lo que la consola le mostrará el objeto en memoria en su lugar, y sí, cuando lo mira, b ya está adjunto a a.

Miao Siyu
fuente
Sé que esta pregunta tiene 3 años, pero ahora mismo tengo el mismo problema: serializar el objeto no me funciona porque es demasiado complicado. Estoy detectando un evento que intenta acceder a sus datos, pero de alguna manera no tiene datos en el código, pero en console.log tiene datos.
Skeec