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.