我目前正在阅读Trevor Burnham的Async Javascript。到目前为止,这是一本很棒的书。
他谈到这个片段和console.log是“async'在Safari和Chrome控制台中。不幸的是我无法复制这个。这是代码:
var obj = {};
console.log(obj);
obj.foo = 'bar';
// my outcome: Object{}; 'bar';
// The book outcome: {foo:bar};
如果这是异步,我会预期结果会成为书籍的结果。 console.log()被放入事件队列中,直到所有代码被执行,然后它被运行并且它将具有bar属性。
虽然它正在同步运行但
我运行此代码错了吗? console.log实际上是异步吗?
答案 0 :(得分:79)
console.log
未标准化,因此行为相当未定义,并且可以在开发人员工具的发行版之间轻松更改。你的书很可能已经过时,我的答案也很快就会过时。
对于我们的代码,console.log
是否异步是没有任何区别的,它不提供任何类型的回调;并且在调用函数时始终引用和计算传递的值。
我们真的不知道接下来会发生什么(好吧,我们可以,因为Firebug,Chrome Devtools和Opera Dragonfly都是开源的)。控制台需要将记录的值存储在某处,它将在屏幕上显示它们。渲染将异步发生(被限制为速率限制更新),以及将来与控制台中已记录对象的交互(如扩展对象属性)。
因此控制台可能克隆(序列化)您记录的可变对象,或者它将存储对它们的引用。第一个不适用于深层物体。此外,至少控制台中的初始渲染可能会显示对象的“当前”状态,即记录时的状态 - 在您的示例中,您会看到Object {}
。
但是,当您展开对象以进一步检查其属性时,控制台可能只存储了对象及其属性的引用,现在显示它们将显示它们当前(已经变异)的状态。如果您点击+
,您应该可以在示例中看到bar
属性。
以下是bug report中发布的屏幕截图,用于解释其“修复”:
因此,某些值可能在记录后很长时间被引用,并且这些值的评估相当 lazy (“需要时”)。这个差异最着名的例子是在Is Chrome's JavaScript console lazy about evaluating arrays?问题中处理的。解决方法是确保始终记录对象的序列化快照,例如:做console.log(JSON.stringify(obj))
。但这仅适用于非圆形和相当小的物体。另请参阅How can I change the default behavior of console.log? (*Error console in safari, no add-on*)。
答案 1 :(得分:1)
使用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太复杂了#39;到' stringify'所以控制台会向你显示内存对象,是的,当你看它时,b已经被附加到了。
答案 2 :(得分:1)
这实际上不是问题的答案,但对于那些偶然发现这篇文章的人来说可能会很方便,并且发表评论的时间太长了:
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
都是以某种方式异步的,因此您可能希望在某些情况下使用类似的功能。