你不知道的console.log()
背景
偶然在使用JavaScript做题时发现了一个关于console.log()的坑:
1 |
|
理论上在浏览器的控制台中会输出:
1 |
|
但是,实际上浏览器的输出:
两次输出的数组竟然都是**[0,2,3]**。
但是在刷新浏览器后:
发现输出结果是正确的,但是在点击下拉框后发现竟然和输出的数组对不上。
而后我将同样的代码使用node进行输出:
发现输出结果又是正确的。
至此可以发现输出结果与运行环境有关,应该是浏览器中console.log()中的问题。
探索过程
然后,通过控制台进行调试,发现在调试过程中,数组a其实发生了变化。这就很奇怪了,为什么调试过程中输出是符合预期的呢?
之后询问了其它大佬,提出过 可以使用JSON.stringify()进行处理,照做之后发现输出结果是正确的:
为什么通过JSON.stringify()进行处理后,输出结果又是正确的呢?
在查找了相关资料后,发现了原因所在。
《你不知道的JavaScript-中卷》第二部分第一章中写道:
并没有什么规范或一组需求指定 console.* 方法族如何工作——它们并不是 JavaScript 正式的一部分,而是由宿主环境(请参考本书的“类型和语法”部分)添加到 JavaScript 中的。 因此,不同的浏览器和 JavaScript 环境可以按照自己的意愿来实现,有时候这会引起混淆。 尤其要提出的是,在某些条件下,某些浏览器的 console.log(..) 并不会把传入的内容立 即输出。出现这种情况的主要原因是,在许多程序(不只是 JavaScript)中,I/O 是非常低 速的阻塞部分。所以,(从页面 /UI 的角度来说)浏览器在后台异步处理控制台 I/O 能够提高性能,这时用户甚至可能根本意识不到其发生。
书中举了一个例子:
下面这种情景不是很常见,但也可能发生,从中(不是从代码本身而是从外部)可以观察到这种情况:
1 |
|
我们通常认为恰好在执行到 console.log(..) 语句的时候会看到 a 对象的快照,打印出类 似于 { index: 1 } 这样的内容,然后在下一条语句 a.index++ 执行时将其修改,这句的执行会严格在 a 的输出之后。
多数情况下,前述代码在开发者工具的控制台中输出的对象表示与期望是一致的。但是, 这段代码运行的时候,浏览器可能会认为需要把控制台 I/O 延迟到后台,在这种情况下, 等到浏览器控制台输出对象内容时,a.index++ 可能已经执行,因此会显示 { index: 2 }。 到底什么时候控制台 I/O 会延迟,甚至是否能够被观察到,这都是游移不定的。如果在调试的过程中遇到对象在 console.log(..) 语句之后被修改,可你却看到了意料之外的结果, 要意识到这可能是这种 I/O 的异步化造成的.
解决办法
- 如果遇到这种少见的情况,最好的选择是在 JavaScript 调试器中使用断点, 而不要依赖控制台输出。
- 次优的方案是把对象序列化到一个字符串中,以强制执行一次“快照”,比如通过 JSON.stringify(..)。
- 本文作者:芝叶
- 本文链接:https://yeatsczx.github.io/2022/08/13/%E4%BD%A0%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84console-log/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!