Console.log() async или sync?

В настоящее время я читаю Async Javascript Тревором Бернем. До сих пор это была замечательная книга.

Он говорит об этом фрагменте, а console.log - "асинхронный" в консоли Safari и Chrome. К сожалению, я не могу воспроизвести это. Вот код:

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

Если бы это было асинхронно, я бы ожидал, что результат будет результатом книг. console.log() помещается в очередь событий, пока не будет выполнен весь код, тогда он будет запущен и будет иметь свойство bar.

Появляется, хотя он работает синхронно.

Я запускаю этот код неправильно? Действительно ли console.log async?

Ответ 1

console.log не стандартизирован, поэтому поведение довольно неопределенное и может быть легко изменено от выпуска к выпуску инструментов разработчика. Ваша книга, скорее всего, устарела, как и мой ответ в ближайшее время.

Для нашего кода не имеет значения, является ли console.log асинхронным или нет, он не обеспечивает какого-либо обратного вызова или около того; и на значения, которые вы передаете, всегда ссылаются и вычисляют во время вызова функции.

Мы действительно не знаем, что произойдет тогда (хорошо, мы могли бы, так как Firebug, Chrome Devtools и Opera Dragonfly все с открытым исходным кодом). Консоль должна будет где-то хранить записанные значения и отображать их на экране. Рендеринг будет происходить точно асинхронно (будучи ограниченным обновлениями с ограничением скорости), как и будущие взаимодействия с зарегистрированными объектами в консоли (например, расширение свойств объекта).

Таким образом, консоль может либо клонировать (сериализовать) изменяемые объекты, которые вы записали в журнал, либо хранить ссылки на них. Первый не очень хорошо работает с глубокими/большими объектами. Кроме того, по крайней мере начальный рендеринг в консоли, вероятно, покажет "текущее" состояние объекта, то есть то, когда он был зарегистрирован - в вашем примере вы видите Object {}.

Однако когда вы расширяете объект для дальнейшей проверки его свойств, вполне вероятно, что консоль будет хранить только ссылку на ваш объект и его свойства, и теперь при их отображении будет отображаться их текущее (уже измененное) состояние. Если вы нажмете на +, вы сможете увидеть свойство bar в вашем примере.

Вот скриншот, который был опубликован в отчете об ошибке, чтобы объяснить их "исправление":

Таким образом, на некоторые значения можно ссылаться задолго до их регистрации, и их оценка довольно ленива ("при необходимости"). Наиболее известный пример такого несоответствия рассматривается в вопросе : ленива ли консоль JavaScript в Chrome при оценке массивов?

Обходной путь должен всегда регистрировать сериализованные снимки ваших объектов, например, с помощью console.log(JSON.stringify(obj)). Это будет работать только для некруглых и довольно маленьких объектов. Смотрите также Как я могу изменить поведение по умолчанию console.log в Safari? ,

Лучшее решение - использовать точки останова для отладки, когда выполнение полностью останавливается, и вы можете проверить текущие значения в каждой точке. Используйте ведение журнала только с сериализуемыми и неизменными данными.

Ответ 2

При использовании 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

в первой ситуации объект достаточно прост, поэтому консоль может "сжимать" его, а затем представлять вам; но в других ситуациях a слишком "сложный", чтобы "подкрепить", поэтому консоль покажет вам объект памяти, и да, когда вы посмотрите на него, b уже привязан к.