console.log() асинхронный или синхронизированный?

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

Он говорит о том, что этот фрагмент и 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 действительно асинхронным?

2 ответа

Решение

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

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

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

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

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

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

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

На самом деле это не ответ на вопрос, но он может быть полезен тем, кто наткнулся на этот пост, и он был слишком длинным, чтобы оставлять комментарий:

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

Это создает псевдосинхронную версию console.log, но с теми же оговорками, что и в принятом ответе.

Поскольку на данный момент кажется, что большинство браузеров console.logв некотором роде асинхронны, вы можете использовать такую ​​функцию в определенных сценариях.

При использовании 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 слишком "сложен" для "stringify", поэтому консоль покажет вам объект в памяти, и да, когда вы посмотрите на него, b уже присоединен к a.

Другие вопросы по тегам