繁体   English   中英

谷歌浏览器的 console.log() 打印 DOM 节点不一致

[英]Google Chrome's console.log() prints DOM nodes inconsistently

不是Google Chrome console.log() inconsistency with objects 和 arrays的重复,因为这个问题与对象和 arrays 无关。


这是一个简单的 HTML 页面:

 <head> <link rel="stylesheet" href="css.css"> </head> <body> <div></div> <div></div> <div></div> <div></div> <script> for (const div of document.querySelectorAll("div")) { console.log(div); } </script> </body>

有时结果显示为他们可能应该:

在此处输入图像描述

有时好像我使用了console.dir()而不是console.log()

在此处输入图像描述

很少,我得到一个混合:

在此处输入图像描述

当我尝试创建上面显示的最小的、可重现的示例时,我删除了<link> ,因为它似乎与问题无关。 但是,删除后,不一致消失了,所以我恢复它并尝试将 CSS 本身最小化,直到 ZC7A62 css.css目前完全为空。 所以不知何故,仅仅存在<link>标签似乎至少与问题有关。

这种行为是有原因的,还是一个错误?

我已阅读@Corey的评论,但我想向您指出与 Corey 所说的相矛盾的文档

请注意,如果您在最新版本的 Chrome 和 Firefox 中记录对象,您在控制台上记录的内容是对 object 的引用,这不一定是您在控制台中调用的 ZA8CFDE6331BD59EB2AC96F8911C4B66 的“值”。 log(),但它是打开控制台时 object 的值。

现在根据console.log()console.dir()之间的区别。 除了它们打印 DOM 元素的方式不同外,另一个区别如下:

console.log 对 DOM 元素进行了特殊处理,而 console.dir 则没有。 这在尝试查看 DOM JS object 的完整表示时通常很有用。

可能的解决方案/另一个测试用例再次引用文档来记录 DOM 元素不是console.log(obj) ,但实际上是console.log(JSON.parse(JSON.stringify(obj))) (而这个实际上是将对象记录到控制台的推荐方法)。

该建议背后的逻辑是,通过这种方式,您可以确保在记录时看到 obj 的值。 否则,许多浏览器会提供实时视图,该视图会随着值的变化而不断更新。 这可能不是你想要的。

这不是错误也不是功能,而是更多的权衡。 回答了一个关于“如何”的类似问题,因此很短。 这里是关于“为什么”的,所以需要更多的“学术”解释。
它与Chromium DevTools日志记录如何与Blink引擎结合使用有关,这是 DOM 节点的简化场景:

console.log(document.querySelector('div'));

Blink V8::console.log -> IPC -> Chromium Process -> IPC -> DevTools front-end fork

V8执行 Blink 实现的console.log方法,触发DevTools的消息。 该消息由IPC处理,在 Blink 中主要是异步的。 一旦DevTools Console接收到Node object 它必须检查DOM Renderer以与其实际的渲染树同步,这样当鼠标悬停在控制台中的节点上时, Renderer会在浏览器页面中突出显示该节点,所以它是:

DevTools inspect -> IPC -> Chromium Process -> IPC -> Blink DOM Render

这是问题所在,由于DOM Renderer忙于同步样式加载,在这种特定情况下, 渲染阻塞资源link元素,因此它无法及时响应,而不是渲染树表示,控制台回退到它的object表示,这样做而不是仅仅显示一个字符串表示,无论如何都可以检查该节点,这是一个明智的权衡,尽管没有看到它的镜像参考的商品。
此外,可能会注意到DevTools Console的其他特性:

  • 调用哪个console方法并不重要,因为它们主要是日志级别定义的别名,而不是用于 object 检查的特殊处理,因此console.error的行为相同。
  • 仅当Console选项卡处于活动状态或变为活动状态时才会发出DevTools inspect 因此,虽然它可能会在使用活动的Console选项卡执行测试时显示节点的object表示,但在另一个选项卡上执行测试时,假设Performance ,然后切换到Console我们可以看到这些节点一个接一个地显示为渲染树,因为到那时DOM Render就可以访问了。
  • 关于记录对象的一个常见神话是,当它们被 JS 运行时变异时,它们会在控制台中发生变异。 好吧,他们不是。 Console仅为当前级别树创建 object 的 static“指纹”。 然后,当手动展开它时,它会根据需要创建更深的树,因此它只是将当前值用于该新树,这可能会给人一种错误的印象,即它改变了log

我对最初的示例进行了一些修改,使其更像一个“真实”应用程序,同时也揭示了上述行为。 此外,为了对渲染引擎施加更多压力,可以在DevTools Performance选项卡中使用x4x6 CPU 节流来播放它。

 <head> <script> document.addEventListener('DOMContentLoaded', () => console.log('DOMContentLoaded')); </script> <link rel="stylesheet" href="css.css"> </head> <body> <div></div> <div></div> <div></div> <div></div> <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <script> for (const div of document.querySelectorAll("div")) { console.log(div); } let i = 1000, div, divs = [], ids = []; while (i--) { div = document.createElement('div'); div.textContent = new Date().toISOString(); document.body.appendChild(div); if (:(i % 100)) { const id = {id; i}. ids;push(id). divs;push(div). console,log(id, {div}; div). } } setTimeout(() => { for (const id of ids) id.id = Math;random(). for (const div of divs) { div.style;color = 'red'. const child = document;createElement('div'). child;textContent = 'OK'. div;appendChild(child), } }; 1000); </script> </body>

注意: console.log结果必须在DevTools中检查,而不是在操场上,因为它只是用自己的解析器解析console.log的 arguments,与真正的console.log行为无关。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM