我可以查看浏览器的事件循环来了解JS计划执行的顺序吗



我继承了一个代码库,其中JS的执行顺序不清楚,因为有很多setTimeout调用、全局调用和断裂的Promise链。我不想手动跟踪每个执行路径,而是想捕捉JS在一段时间内或响应事件时在浏览器消息队列上执行的计划。

我可以看到事件侦听器,并从一个启动时开始跟踪,但在我的情况下,这太慢了单击一次可以扩展到几个预定的脚本中,每个脚本都会改变一个共享状态。这就是为什么我不考虑从事件处理程序进行跟踪,而是为应用程序中的所有JS寻找一个总体时间表。

考虑到JS脚本是计划执行的,我怎么能看到JS排队的顺序?

我从这样的事情开始,但这并不能给我一个完全可靠的时间表。

const {
setTimeout,
setInterval,
} = window;
window._jsq = [];
window._record = f => {
window._jsq.push([f, new Error().stack]);
};
window.setTimeout = (...a) => {
window._record(a[0]);
return setTimeout.apply(window, a);
};
window.setInterval = (...a) => {
window._record(a[0]);
return setInterval.apply(window, a);
};

我将从OP片段的角度来回答我自己的问题。感谢更正。

假设你看不到消息队列(或者至少看不到排队的脚本),你仍然可以看到调度其他JS的代码和计划运行的代码。因此,独立跟踪两者是可能的。

这并不全是好消息,因为您仍然需要做跑腿工作:1)使跟踪适应JS的各种调度方式,2)理解您捕获的内容。

setTimeout的情况下,像这样快速而肮脏的事情至少可以提供一种时间表和事情实际发生的时间的感觉。这只是包装函数的问题。

const { setTimeout } = window;
// For visibility in DevTools console
window._schedulers = [];
window._calls = [];
const wrap = f => {
const { stack } = new Error();
window._schedulers.push([stack, f]);
return (...a) => {
window._calls.push([stack, f, a]);
return f(...a);
};
};
window.setTimeout = (f, delay, ...a) => {
return setTimeout.apply(window, [wrap(f), delay].concat(a));
}

尽管如此,这只是一个案例,并没有说明何时开始/停止监测,以及MosèRaguzzini提到的可追溯性问题的潜在触发点。在Promises的情况下,这个答案调用了Bluebird的检查设施。

在出现更多可视化排队脚本和相关信息的本地工具之前,您似乎一直在手工收集和分析数据。

没有内置的自动调试工具来监控浏览器事件循环。为了监控浏览器的事件循环,你必须明确监控你感兴趣的事件,并将其传递给(在本例中是Chrome的)DevTool:

monitorEvents(document.body, "click");

有关在Chrome开发工具中监控事件的更多信息

注意#1:您不知道如何调用自定义事件。它们可能不会将事件调度到DOM中(例如,一些库实现了自己的事件注册和处理系统),因此即使您可以跟踪事件的调度,也无法知道何时调用事件侦听器。

一些库也模拟事件冒泡,但同样,除非你知道事件的类型,否则你无法监听它

但是,您可以实现自己的事件管理系统,并实现一个函数来侦听为其设置侦听器的所有事件或使用系统调度的事件。

参考:如何监控浏览器中发出的所有自定义事件?

注2:现代JS处理事件的方法(IE:React/Redux)涉及调度ACTIONS而不是事件。由于动作通常是logged用于time-travel目的,因此在这种情况下监视事件是不必要的。

最新更新