console.log() 异步还是同步?

2022-08-30 05:04:10

我目前正在阅读Trevor Burnham的Async Javascript。到目前为止,这是一本很棒的书。

他谈到了这个片段和控制台.log在Safari和Chrome控制台中是“异步的”。不幸的是,我无法复制这一点。代码如下:

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

如果这是异步的,我会预期结果将是书籍的结果。console.log() 被放入事件队列中,直到执行所有代码,然后运行它,它将具有 bar 属性。

它似乎正在同步运行。

是我运行了此代码错误吗?控制台.log实际上是异步的吗?


答案 1

console.log没有标准化,因此行为相当不确定,并且可以轻松地从开发人员工具的发布到发布进行更改。你的书可能已经过时了,我的答案可能很快就会过时。

对于我们的代码,无论是否是异步的,它没有任何区别,它不提供任何类型的回调等等;并且您传递的值始终在您调用函数时被引用和计算。console.log

我们真的不知道会发生什么(好吧,我们可以,因为Firebug,Chrome Devtools和Opera Dragonfly都是开源的)。控制台需要将记录的值存储在某个位置,并在屏幕上显示它们。渲染肯定会异步发生(被限制为速率限制更新),将来与控制台中记录的对象的交互也是如此(如展开对象属性)。

因此,控制台可能会克隆(序列化)您记录的可变对象,或者存储对它们的引用。第一个不能很好地处理深/大型对象。此外,至少在控制台中的初始渲染可能会显示对象的“当前”状态,即记录对象时的状态 - 在您的示例中,您会看到。Object {}

但是,当您展开对象以进一步检查其属性时,控制台可能只存储了对对象及其属性的引用,现在显示它们将显示其当前(已突变)状态。如果单击 ,则应该能够在示例中看到该属性。+bar

以下是在错误报告中发布的屏幕截图,用于解释他们的“修复”:

因此,某些值可能会在记录很久之后被引用,并且这些值的计算相当懒惰(“当需要时”)。这种差异的最着名的例子是在以下问题中处理的:Chrome的JavaScript控制台是否懒于评估数组?

解决方法是确保始终记录对象的序列化快照,例如,通过执行 .不过,这仅适用于非圆形和相当小的对象。另请参阅如何在 Safari 浏览器中更改主机.log的默认行为?console.log(JSON.stringify(obj))

更好的解决方案是使用断点进行调试,其中执行完全停止,您可以检查每个点的当前值。仅对可序列化和不可变数据使用日志记录。


答案 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

由于目前大多数浏览器的's似乎在某种程度上是异步的,因此您可能希望在某些情况下使用这样的函数。console.log