Log()异步还是同步?

我现在正在读特雷弗 · 伯纳姆的 异步 Javascript,这是一本很棒的书。

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

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

If this was async, I would anticipate the outcome to be the books outcome. console.log() is put in the event queue until all code is executed, then it is ran and it would have the bar property.

虽然它是同步运行的。

我运行这段代码是错误的吗? console. log 实际上是异步的吗?

59225 次浏览

console.log不是标准化的,因此行为是相当未定义的,并且可以很容易地从一个版本更改到另一个版本的开发人员工具。你的书可能已经过时了,我很快就会给你答复。

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

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

因此,控制台可以克隆(序列化)您记录的可变对象,或者存储对它们的引用。第一种方法不能很好地处理深度/大型对象。此外,至少控制台中的初始呈现可能会显示对象的“当前”状态,也就是它被登录时的状态——在您的示例中可以看到 Object {}

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

下面是在 漏洞报告上发布的解释他们“修复”的截图:

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

一个解决方案是确保始终记录对象的序列化快照,例如通过执行 console.log(JSON.stringify(obj))。不过,这仅适用于非圆形和相当小的物体。参见 如何在 Safari 中更改 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

在第一种情况下,对象很简单,所以控制台可以“ stringify”它然后呈现给你; 但在其他情况下,a 太“复杂”而不能“ stringify”,所以控制台将显示内存中的对象,而且是的,当你看到它时 b 已经被附加到。

这并不是对这个问题的真正回答,但是对于那些偶然发现这篇文章的人来说,它可能会很方便,而且这篇文章太长以至于无法发表评论:

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在某种程度上是异步的,因此您可能希望在某些场景中使用类似的函数。