如何解决异步函数脚本中console.group()分组混乱的问题?
如何解决异步函数脚本中console.group()分组混乱的问题?
这个问题我太懂了!异步操作打断console分组的情况真的超级影响调试体验,尤其是多个实例并行执行的时候,日志完全乱成一锅粥😅。
问题根源
你遇到的核心问题是JavaScript的事件循环机制:当await this.asyncMethod()执行时,当前函数会暂停,把控制权交还给事件循环,这时候第二个new C('green')的同步代码会立刻执行,它的console.groupCollapsed和run日志就会插在第一个实例的异步操作中间,等第一个实例的setTimeout完成后,它的asyncMethod日志才会输出,最终导致分组完全混乱。
下面给你两个实用的解决方案,你可以根据需求选择:
方案一:让实例按顺序执行(实时输出日志)
如果你可以接受两个实例的代码按顺序执行(先执行完红色实例的所有操作,再执行绿色实例),可以用一个全局Promise队列来控制执行顺序,这样每个实例的console分组就不会被打断:
// 全局执行队列,确保实例按顺序执行 let executionQueue = Promise.resolve(); class C { color; colorName; constructor(color) { this.color = `font-weight: strong; color: ${color}`; this.colorName = color; // 将当前实例的run方法加入队列,等待前一个实例完成后再执行 executionQueue = executionQueue.then(() => this.run()); } async run() { console.groupCollapsed('%c Class C ', this.color, this.colorName); console.log('%c run', this.color); await this.asyncMethod(); this.syncMethod(); console.groupEnd(); } async asyncMethod() { return new Promise((resolve) => { setTimeout(() => { console.log('%c asyncMethod', this.color, this.colorName); resolve(); }, 99); }); } syncMethod() { console.group('%c syncMethod', this.color, this.colorName); this.subSyncMethod(); console.groupEnd(); } subSyncMethod() { console.log('%c subSyncMethod', this.color, this.colorName); } } new C('red'); new C('green');
这个方案的原理是让每个实例的run方法等待队列前的所有操作完成后再执行,这样日志会严格按照实例顺序输出,分组完全整齐,和你想要的预期结果一致。
方案二:日志队列延迟输出(实例并行执行)
如果你需要两个实例并行执行,但又想保持分组完整,可以给每个实例添加一个日志队列,先把所有console操作存起来,等实例的所有异步操作完成后,再一次性输出所有日志:
class C { color; colorName; // 私有日志队列,存储当前实例的所有console操作 #logQueue = []; constructor(color) { this.color = `font-weight: strong; color: ${color}`; this.colorName = color; // 执行逻辑,完成后刷新日志 this.run().then(() => this.#flushLogs()); } async run() { this.#logQueue.push(['groupCollapsed', '%c Class C ', this.color, this.colorName]); this.#logQueue.push(['log', '%c run', this.color]); await this.asyncMethod(); this.syncMethod(); this.#logQueue.push(['groupEnd']); } async asyncMethod() { return new Promise((resolve) => { setTimeout(() => { this.#logQueue.push(['log', '%c asyncMethod', this.color, this.colorName]); resolve(); }, 99); }); } syncMethod() { this.#logQueue.push(['group', '%c syncMethod', this.color, this.colorName]); this.subSyncMethod(); this.#logQueue.push(['groupEnd']); } subSyncMethod() { this.#logQueue.push(['log', '%c subSyncMethod', this.color, this.colorName]); } // 一次性执行所有日志操作 #flushLogs() { this.#logQueue.forEach(([method, ...args]) => { console[method](...args); }); } } new C('red'); new C('green');
这个方案的好处是两个实例的代码会并行执行,不会互相阻塞,但日志会等到每个实例的所有异步操作完成后才输出,这样每个实例的分组都是完整的,不会被其他实例的日志打断。
备注:内容来源于stack exchange,提问作者iiic
相关产品推荐
相关产品推荐

