console.log () asynchrone ou synchro?


93

Je lis actuellement Async Javascript par Trevor Burnham. Cela a été un excellent livre jusqu'à présent.

Il dit que cet extrait et console.log sont «asynchrones» dans la console Safari et Chrome. Malheureusement, je ne peux pas reproduire cela. Voici le code:

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

Si c'était asynchrone, j'anticiperais que le résultat serait celui des livres. console.log () est placé dans la file d'attente des événements jusqu'à ce que tout le code soit exécuté, puis il est exécuté et il aurait la propriété bar.

Il semble bien qu'il fonctionne de manière synchrone.

Est-ce que j'exécute mal ce code? Console.log est-il réellement asynchrone?


@thefourtheye: Non, donc je devrais probablement simplement supprimer mon commentaire.
cookie monster

1
Je l'ai vu se produire dans Chrome. Si vous console.log un objet simple puis modifiez immédiatement quelque chose dans l'objet, le console.log()n'affiche pas toujours l'ancienne valeur. La solution de contournement si cela vous arrive est de convertir tout ce que vous essayez de console.log()faire en une chaîne immuable, donc non sujette à ce problème. Ainsi, par expérience, console.log()certains problèmes asynchrones sont probablement liés au marshaling des données au-delà des limites du processus. Ce n'est pas le comportement prévu, mais c'est un effet secondaire de la façon dont console.log()fonctionne en interne (je le considérerais personnellement comme un bogue).
jfriend00


1
@bergi il m'a juste fallu 10 minutes pour trouver cette dupe (même si je connaissais le nom exact), probablement parce qu'elle est dupeclosed. Ne pourrions-nous pas simplement échanger le duplicata, pour que l'autre soit la dupe ...?
Jonas Wilms

1
@JonasWilms J'ai maintenant rouvert cette question (voir historique ). Je ne pense pas qu'il s'agisse de doublons, j'utilise La console JavaScript de Chrome est-elle paresseuse pour évaluer les tableaux? comme cible canonique pour les problèmes impliquant spécifiquement un tableau.
Bergi

Réponses:


114

console.logn'est pas standardisé, donc le comportement est plutôt indéfini et peut être changé facilement d'une version à l'autre des outils de développement. Votre livre sera probablement obsolète, comme ma réponse pourrait bientôt.

Pour notre code, cela ne fait aucune différence que ce console.logsoit asynchrone ou non, cela ne fournit aucun type de rappel ou autre; et les valeurs que vous transmettez sont toujours référencées et calculées au moment où vous appelez la fonction.

Nous ne savons pas vraiment ce qui se passe alors (OK, nous pourrions, puisque Firebug, Chrome Devtools et Opera Dragonfly sont tous open source). La console devra stocker les valeurs enregistrées quelque part et les affichera à l'écran. Le rendu se produira de manière asynchrone à coup sûr (étant limité aux mises à jour de limite de débit), tout comme les interactions futures avec les objets journalisés dans la console (comme l'expansion des propriétés d'objet).

Ainsi, la console peut soit cloner (sérialiser) les objets mutables que vous avez consignés, soit stocker des références à ceux-ci. Le premier ne fonctionne pas bien avec les objets profonds / grands. De plus, au moins le rendu initial dans la console montrera probablement l'état "actuel" de l'objet, c'est-à-dire celui lorsqu'il a été connecté - dans votre exemple que vous voyez Object {}.

Cependant, lorsque vous développez l'objet pour inspecter davantage ses propriétés, il est probable que la console aura uniquement stocké une référence à votre objet et à ses propriétés, et les afficher maintenant affichera alors leur état actuel (déjà muté). Si vous cliquez sur +, vous devriez pouvoir voir la barpropriété dans votre exemple.

Voici une capture d'écran qui a été publiée dans le rapport de bogue pour expliquer leur «correctif»:

Ainsi, certaines valeurs peuvent être référencées longtemps après avoir été consignées, et leur évaluation est plutôt paresseuse («si nécessaire»). L'exemple le plus célèbre de cet écart est traité dans la question La console JavaScript de Chrome est-elle paresseuse pour évaluer les tableaux?

Une solution de contournement consiste à vous assurer de toujours consigner les instantanés sérialisés de vos objets, par exemple en faisant console.log(JSON.stringify(obj)). Cela fonctionnera uniquement pour les objets non circulaires et plutôt petits. Voir aussi Comment puis-je changer le comportement par défaut de console.log dans Safari? .

La meilleure solution consiste à utiliser des points d'arrêt pour le débogage, où l'exécution s'arrête complètement et vous pouvez inspecter les valeurs actuelles à chaque point. Utilisez la journalisation uniquement avec des données sérialisables et immuables.


2
J'ai eu le même problème avec console.log n'étant pas asynchrone. l'utilisation de JSON.stringify l'a corrigé pour moi
russiansummer

À partir de 2019, pouvons-nous dire qu'il console.logest toujours asynchrone dans Chrome car il avait 8 ans (voir stackoverflow.com/questions/7389069/… ), la seule chose qui change est que maintenant Chrome produit un instantané de l'objet de référence au l'heure à laquelle vous appelez console.log(si vous développez l'objet journalisé, vous verrez ses propriétés et valeurs finales après les opérations de mutation que vous avez effectuées après console.log), ou est-il en console.logeffet synchrone?
tonix

@tonix Oui, il est peu probable que ce comportement soit modifié pour les raisons exposées dans ma réponse. Ce n'est pas un bogue, c'est juste comment fonctionne un débogueur / inspecteur interactif.
Bergi

Si vous utilisez JSON.parse(JSON.stringify(obj))comme mentionné dans le commentaire ici, vous obtenez un instantané sous forme d'objet, au lieu d'une chaîne.
Wilt

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

2

Ce n'est pas vraiment une réponse à la question, mais cela pourrait être pratique pour quelqu'un qui est tombé sur ce post, et c'était trop long pour mettre un commentaire:

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

Cela crée une version pseudo-synchrone de console.log, mais avec les mêmes mises en garde que celles mentionnées dans la réponse acceptée.

Puisqu'il semble que, pour le moment, la plupart des navigateurs console.logsoient asynchrones d'une certaine manière, vous voudrez peut-être utiliser une fonction comme celle-ci dans certains scénarios.


0

Lors de l'utilisation de 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

dans la première situation, l'objet est assez simple, donc la console peut le «stringifier» puis vous le présenter; mais dans les autres situations, a est trop «compliqué» pour «stringifier», donc la console vous montrera l'objet en mémoire à la place, et oui, quand vous le regardez, b est déjà attaché à a.


Je sais que cette question a 3 ans, mais pour le moment, je rencontre le même problème - la sérialisation de l'objet ne fonctionne pas pour moi car c'est trop compliqué. J'attrape un événement essayant d'accéder à ses données, mais d'une manière ou d'une autre, il n'a pas de données dans le code, mais dans console.log, il contient des données.
Skeec
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.