BackburnerJS / backburner.js

A rewrite of the Ember.js run loop as a generic microlibrary
MIT License
392 stars 80 forks source link

Add support for Chrome's ASync Stack Tagging API #404

Open davidtaylorhq opened 1 year ago

davidtaylorhq commented 1 year ago

https://developer.chrome.com/blog/devtools-modern-web-debugging/#linked-stack-traces

This enables the Chrome developer tools to link the stack traces of the original event scheduling and the eventual execution on the runloop. This is available in Chrome 106 and above.

To protect production performance, this is disabled-by-default, but can be enabled by setting Backburner.ASYNC_STACKS = true. Applications / frameworks could choose to enable this by default in development modes.


Given the example code:

let bb = new Backburner(['afterRender']);

function renderSomething(){
  debugger;
}

function simulateClick(){
  bb.schedule("afterRender", renderSomething);
}

bb.run(() => {
  simulateClick()
});
Stack Comparison

With backburner.js added to Chrome's 'framework ignore list', it looks like this:

Screenshot 2022-10-10 at 12 57 15

The result is somewhat similar to #340, but this new API allows us to implement async stacks without introducing any behaviour change.

When the flag is disabled, this commit does not have any measurable performance impact. Testing in the latest stable chrome (via #403) both before and after, I see 2.07 million op/s in the "Schedule & Flush - function" benchmark.

When the flag is enabled, there is some performance impact. In chrome, with dev tools closed, it makes the micro-benchmark about 60% slower (2,000k op/s → 870k op/s). With dev tools open, it makes the micro-benchmark about 93% slower (2,000k op/s → 138k op/s). Given that performance hit, we probably should not enable this flag by default in production.

Taking Discourse as a real-world example, an initial render of the application results in about 250 jobs being added to the runloop. So even in the worst case 'dev tools open' scenario, with a little maths based on the op/s, we're talking about a 1.7ms slowdown (0.1ms with flag disabled, 1.8ms with flag enabled). For us, that tiny slowdown in development would definitely be worth it for the improved developer experience. It may even make sense as a default for Ember when in Debug mode.