console.log是异步的吗?

本文探讨了在Chrome浏览器中使用console.log打印JavaScript对象时遇到的同步问题。通过实验发现,控制台打开与否会影响输出结果,文章详细解释了这一现象的原因,并提出了解决方案。

今晚我加的一个前端群里有人问了这样一个问题,下面这段代码在Chrome中运行:

<!DOCTYPE html>
<html lang="en">
    <head>
    <meta charset="UTF-8">
    <title></title>
    </head>
    <body>
    <script>
            var a = {name: '1'};
            console.log(a);
            a.name = '2';
            console.log(a);
    </script>
    </body>
</html>

打开控制台后,却发现运行结果是这样的:

Object
    name: "2"
    __proto__: Object
Object
    name: "2"
    __proto__: Object

这个结果不符合我们所期望的第一个输出是name: "1"

难道console.log是异步的?

可是当我将那段JavaScript代码粘贴到控制台直接运行,或是打开控制台后刷新一遍网页,运行结果就会变成:

Object {name: "1"}
Object {name: "2"}

这正是我们所期望的结果。

为什么会这样?

因为代码在运行的时候控制台没有打开

首先明确一点,a所储存的是一个引用类型值的地址,所有对a的操作都会具体到这个地址所对应的那个对象上。其次,console并不是JavaScript提供的对象,而是浏览器的控制台提供的。这具体到不同的浏览器,比如Chrome中是由Devtool的控制台提供,Firefox中是由Firebug的控制台提供。

在Chrome中,console.log在控制台打开后才起作用,也就是说,当你打开控制台时,console.log才会将之前被传进去的参打印出来。
那么问题来了,在上述代码中,传进console.log中的参是一个地址,当代码执行完毕后,打开控制台,console.log开始起作用,那么它打印出的实际上是已经做完全部处理后的对象。这就相当于这样的执行顺序:

var a = {name: '1'};
a.name = '2';
console.log(a);
console.log(a);

如果是打开控制台再运行代码,那么console.log是直接起作用的,代码会顺序执行,所以所看到的结果是符合期望的。

那么该如何解决这个问题?只能在执行的过程中创建新对象来曲线救国了:

var a = {name: '1'};
console.log(JSON.parse(JSON.stringify(a)));
a.name = '2';
console.log(JSON.parse(JSON.stringify(a)));

这相当于帮浏览器对要被改变的对象存了个快照。

当然,只要你开着控制台来执行代码,那么是不会出现这样的问题的。

最后我认为这不是个BUG,相反这是个节省运算资源的行为。无论控制台是否打开console.log都起作用是十分不妥的。

开着控制台还会出现不符合期望的结果才是BUG,然而早就被修复了。

转载于:https://www.cnblogs.com/sevenskey/p/5476386.html

JavaScript 中,`console.log` 的执行顺序与事件循环机制密切相关。JavaScript 是单线程语言,因此代码的执行顺序可以分为**同步代码**和**异步代码**两大类,其中同步代码总是优先于异步代码执行。 ### 同步代码的执行 同步代码会按照从上到下的顺序依次执行。例如: ```js console.log('同步1'); console.log('同步2'); console.log('同步3'); ``` 输出结果为: ``` 同步1 同步2 同步3 ``` ### 异步代码的执行 异步代码包括 `setTimeout`、`setInterval`、`Promise.then()` 等,它们会被放入事件循环队列中,在同步代码执行完毕后才会执行。 #### 1. `setTimeout` 的执行顺序 `setTimeout` 属于宏任务(macrotask),它会在当前所有同步代码执行完成后,并且经过指定的延迟时间后才被推入事件循环队列。 示例: ```js console.log(1); setTimeout(() => { console.log(2); }, 0); console.log(3); ``` 输出结果为: ``` 1 3 2 ``` 由于 `setTimeout` 是异步的,它会在同步代码执行完之后才执行[^2]。 #### 2. `Promise.then()` 的执行顺序 `Promise.then()` 属于微任务(microtask),它的执行优先级高于宏任务。当一个 `Promise` 被 `resolve` 或 `reject` 后,其对应的 `then` 和 `catch` 回调会立即被加入微任务队列,并在当前同步代码执行完毕后立刻执行。 示例: ```js console.log(1); Promise.resolve().then(() => { console.log(2); }); setTimeout(() => { console.log(3); }, 0); console.log(4); ``` 输出结果为: ``` 1 4 2 3 ``` 这里的关键在于:微任务(如 `Promise.then()`)总是在下一个宏任务(如 `setTimeout`)之前执行[^3]。 #### 3. 综合案例分析 以下是一个更复杂的例子,展示 `console.log`、`setTimeout` 和 `Promise.then()` 的执行顺序: ```js console.log(1); setTimeout(() => { console.log(2); Promise.resolve().then(() => { console.log(3); }); }, 0); console.log(4); new Promise((resolve, reject) => { console.log(5); resolve(); }).then(() => { console.log(6); setTimeout(() => { console.log(7); }); }); console.log(8); ``` 输出结果为: ``` 1 4 5 8 2 3 6 7 ``` 解释如下: - `1`、`4`、`5`、`8` 是同步代码,按顺序执行。 - 接下来是微任务队列中的 `Promise.then()` 执行,即 `3` 和 `6`。 - 最后是宏任务队列中的 `setTimeout`,即 `2` 和 `7`。 ### 总结 JavaScript 的执行顺序遵循以下规则: 1. **同步代码优先执行**。 2. **微任务(如 `Promise.then()`)在当前宏任务结束后立即执行**。 3. **宏任务(如 `setTimeout`)在微任务队列清空后执行**。 通过理解事件循环机制,可以准确预测 `console.log`、`setTimeout`、`Promise.then()` 等操作的执行顺序。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值