console.log是同步还是异步?眼见不一定为实
发布于 5 年前 作者 Telanx 10784 次浏览 来自 分享

分享一下今天做的一次实验! 问题重现:打开浏览器执行以下代码

var a = {b:{c:1}};
console.log(a);
a.b.c = 2;

控制台看到打印出来的是什么?{b:{c:2}}对吗?由此你得出console.log应该是异步的结果。我能告诉你眼见不一定为实么?你所看到的是错误的!拿同样的代码放到node环境下跑你就会发现打印出的是{b:{c:1}}。 是不是感觉很无奈?同一个V8引擎,执行结果最后居然不一样! 事实上,执行结果是一样的,只不过你看到的不一样罢了!原因就出在浏览器控制台所见不一定为实。 尝试把打印的代码换一下,改为console.log(a.b.c)你会发现这次是跟node下一致了。我也不想在此延伸浏览器控制台的问题了,实际上相当于一种懒加载,这也是为什么你可以在控制台无限查看Object的prototype了。 回到问题本身,console.log究竟是同步还是异步?我觉得console.log应该和alert一样是同步的,会阻塞线程执行。丢一个问题这里:

function test() {
console.log('a'); // 为什么加上console.log之后,执行不会报Maximum call stack size exceeded
test();
}
test();
9 回复

你的例子会溢出啊 只是因为多了一个 console.log('a') ,这又是一个 同步调用,假如栈 3W 次溢出,那么意味着起码 3W 次的 console,花费比较久罢了,最后还是会 Maximum call stack size exceeded 的啊

之所以你看不到,是因为输出在stderr了 node a.js 1>stdout.txt 2>stderr.txt

我个人理解哈,在浏览器的控制台是先加载全部代码到内存,然后再逐行执行,在node环境是解释型的逐行执行。 举个例子,比如我写html的时候js代码部分,喜欢把所有的函数体放最后面: test(); function test(){console.log(“test”);} 这样写是不会报错的,因为js代码已经全部加载进内存了,才执行test();所以,我觉得浏览器的控制台的原理和这个一样。。。而node的环境这个我就不解了。。。 哈哈,以上都是我的个人理解,请大神们指教。

其实在 console.log 执行的时候,chrome 会对 log 的对象求一次值,打印出来是 Object ,可以继续展开的。但当你展开控制台中的 Object 的时候,chrome 又会对它求一次值,这一次是显示它的属性。所以才会有前后打印的东西不一样的情况发生,因为对象引用的实体的值改变了。 如果把 console.log(a) 改为 console.log(JSON.stringify(a)), 这时就会输出 {"b":{"c":1}} 是刚开始期望的结果。

探索的精神值得称赞。 而且这故弄玄虚的标题,成功吸引了我的眼球,把我欺骗了进来。 控制台打印出来的只是个对象的引用,你点开它的时候不代表就是console.log执行的时候。 这无法说明什么同步异步的问题。判断同步异步,最浅显的方式也是看它什么时候执行,而不是通过一些输出结果来臆测吧。 alert(test);{function test(){}} //弹出"undefined",而不是"test is not defined",也不是"function ff(){}"。 这种不太按常理,不太容易理解的结果。只是它有自己内部特殊的机制。这样你也可以说alert是异步? 不要用欺骗我的方式来吸引我。

平时没有注意过,不过这种探究的精神值得学习

@Rocket1184 的解释是正确的

关于 console.log 内部的执行是同步还是异步,这个 node 文档里明确了:

Warning: The global console object’s methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

image.png

回到顶部