console.log () асинхронізація чи синхронізація?


93

Зараз я читаю асинхронний 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 насправді асинхронним?


@thefourtheye: Ні, тому я, мабуть, повинен просто видалити свій коментар.
cookie monster

1
Я бачив, як це відбувається в Chrome. Якщо ви console.log простий об'єкт, а потім негайно щось змінити в об'єкті, console.log()не завжди відображається колишнє значення. Навколо цього, якщо це трапляється з вами, є перетворення того, що ви намагаєтесь, на console.log()рядок, який є незмінним, тому ця проблема не підлягає. Отже, з досвіду console.log()є деякі проблеми з асинхронізацією, які, ймовірно, пов’язані з розподілом даних за межами процесу. Це не передбачувана поведінка, а деякий побічний ефект того, як console.log()працює всередині (я б особисто вважав це помилкою).
jfriend00


1
@bergi мені просто знадобилося 10 хвилин, щоб знайти цю дурію (хоча я знав точну назву), можливо, тому, що вона дупклонована. Чи не могли б ми просто поміняти місцями дублікат, щоб другий був дурнем ...?
Jonas Wilms

1
@JonasWilms Зараз я знову відкрив це питання (див. Історію ). Я не думаю, що вони є дублікатами один одного, я використовую. Чи консоль JavaScript на Chrome ледача щодо оцінки масивів? як канонічна ціль для проблем, що стосуються масиву.
Берги

Відповіді:


114

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

Для нашого коду це не має значення console.log, асинхронний чи ні, він не передбачає жодного зворотного дзвінка або близько того; а передані вами значення завжди посилаються та обчислюються під час виклику функції.

Ми насправді не знаємо, що відбувається тоді (добре, ми могли б, оскільки Firebug, Chrome Devtools та Opera Dragonfly - це всі відкриті джерела). Консолі потрібно буде десь зберігати зареєстровані значення, і вона відображатиме їх на екрані. Візуалізація відбуватиметься точно асинхронно (з обмеженням до обмежень швидкості), як і майбутні взаємодії із зареєстрованими об'єктами в консолі (наприклад, розширення властивостей об'єкта).

Отже, консоль може або клонувати (серіалізувати) змінні об’єкти, які ви реєстрували, або вона буде зберігати посилання на них. Перший погано працює з глибокими / великими об’єктами. Крім того, принаймні початковий візуалізація в консолі, ймовірно, відображатиме "поточний" стан об'єкта, тобто той, коли він був зареєстрований - у вашому прикладі ви бачите Object {}.

Однак, коли ви розгортаєте об'єкт для подальшого перевірки його властивостей, цілком ймовірно, що консоль буде зберігати лише посилання на ваш об'єкт та його властивості, а їх відображення тепер відображатиме їх поточний (вже змінений) стан. Якщо натиснути на +, ви зможете побачити barвластивість у вашому прикладі.

Ось знімок екрана, який був опублікований у звіті про помилку, щоб пояснити їх "виправлення":

Отже, на деякі значення можна посилатися ще довго після їх реєстрації, і їх оцінка є досить лінивою ("коли потрібно"). Найвідоміший приклад цієї розбіжності розглядається у питанні Чи лежить консоль JavaScript на Chrome щодо оцінки масивів?

Вирішення полягає в тому, щоб завжди реєструвати серіалізовані знімки ваших об’єктів, наприклад, виконуючи console.log(JSON.stringify(obj)). Однак це буде працювати лише для некруглих і досить дрібних об'єктів. Див. Також Як я можу змінити поведінку за замовчуванням console.log у Safari? .

Кращим рішенням є використання точок зупинки для налагодження, де виконання повністю зупиняється, і ви можете перевірити поточні значення в кожній точці. Використовуйте журналювання лише із серіалізованими та незмінними даними.


2
у мене була та сама проблема, що console.log не був асинхронним. за допомогою JSON.stringify виправив це для мене
russiansummer

Станом на 2019 рік, чи можемо ми сказати, що console.logвін все ще асинхронний у Chrome, оскільки йому було 8 років (див. Stackoverflow.com/questions/7389069/… ), єдине, що змінюється, це те, що тепер Chrome видає знімок посилального об’єкта на під час виклику console.log(якщо розгорнути зареєстрований об'єкт, ви побачите його остаточні властивості та значення після операцій мутації, які ви зробили після console.log), або console.logсправді синхронно?
tonix

@tonix Так, ця поведінка навряд чи буде змінена через причини, викладені в моїй відповіді. Це не помилка, це просто те, як працює інтерактивний налагоджувач / інспектор.
Берги

Якщо ви використовуєте, JSON.parse(JSON.stringify(obj))як також зазначено в коментарі тут, ви отримаєте знімок у вигляді об'єкта, а не рядка.
Вілт

TL; DR.way way way TL
Rick O'Shea

2

Це насправді не відповідь на запитання, але це може бути корисно тому, хто натрапив на цю публікацію, і це було занадто довго, щоб коментувати:

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якимось чином асинхронні, можливо, ви захочете використовувати таку функцію в певних сценаріях.


0

При використанні 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 вже приєднано до a.


Я знаю, що цьому питанню 3 роки, але зараз я стикаюся з тією ж проблемою - серіалізація об’єкта у мене не працює, оскільки це занадто складно. Я ловлю подію, намагаючись отримати доступ до її даних, але якось у коді немає даних, але в console.log він має дані.
Skeec
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.