Open yashjoshi-dotcom opened 1 year ago
Really excited about this!
Some initial thoughts on:
(1) single vs. multiple initiators
A single initiator will be much more valuable than what we have today (nothing), and if it can be the "nearest" or "most immediate" initiator, that will give RUM vendors a huge amount of insight into this dependency tree over what we have today.
If multiple initiators were offered, I'm sure RUM vendors would capture it, but we would have to better understand how to weigh each initiator in importance (so something like ordering of the entries would matter, or additional attributes on the entries list would be needed to understand why each initiator was there).
If we think we'll eventually go down the path of multiple initiators, we may want to start out with an array of initiators, even if we only ever fill it with a single entry to begin with.
(2) on-stack async scripts
I personally don't feel like the complexity of reporting on that is necessary.
(3) wrapping functions
Finally, one challenge existing RUM vendors, analytics scripts and/or security products may have is that JS functions can often be "wrapped" by those libraries (or other 3P resources) and replaced by vendor-supplied functions that do measuring/monitoring/intervention and re-call the original function.
Do you know how the initiator would be reported in this case? I'd be concerned e.g. RUM scripts would find themselves blamed for a lot of the downloads (which is what we see in dev tools, Lighthouse, etc commonly). I'm happy to provide some repro pages to test if you need.
If a single initiator was reporting just the "wrapper library" and the "original" caller was then 2nd in a list of initiators, reporting on multiple initiators instead could be beneficial here. How would a deep stack of e.g. a fetch()
going through multiple scripts get reported?
RE (3), I believe TaskAttribution would work fine, given its (mostly) caller semantics.
^^ @andreubotella @littledan @domenic - FYI RE the caller/registrar semantics discussion
Abstract
The goal of this project is to extend the Resource Timing API to expose initiator information that will point to the resource that triggered the fetch of other resources. This will facilitate developers and RUM Providers to have interesting optimizations to make web apps work much faster.
Identifiers
Every resource gets a unique identifier known as ResourceID. This unique identifier attribute can be derived by combining the already present
[URL]
and the[startTime]
attributes. The proposed algorithm for this will be essentially a string concatenation mechanism that will take the above-mentioned attributes as input and return a string that will be unique for each resource fetch. The ResourceID of the parent resource will be used to populate the Initiator field for every RT entry.Approach
The feature's goal is to enable the creation of dependency trees from RUM (Real User Monitoring) data leading to a better understanding of the resource loading performance. In the basic case, it will be pointing to a particular culprit here which was responsible for loading of a particular resource:
<script>
,<img>
, and<iframe>
tags or by inline scripts, we point the initiator as the HTML document.@import
, a background-image, or a font-face inside a stylesheet, we point to that stylesheet as the initiator for all such resources.For case (3), things can get a little more complex, as there could be various blockers or dependencies that may be on the path for a resource to be loaded.
Examples
Example 1 - On Stack Script
Let's say we have some library code that a carousel relies upon to serve the resources. In such a scenario, if we want to optimize/speed up the loading of the requested resource, having a list of influencers/blockers pointing to both the carousel and library can be potentially more useful.
Example 2 - Preceding Deferred Script
Consider a case where we have the following:
Here buttons.js will block the execution of the carousel, even if it won’t be part of the call stack for any resource loads.
Example 3 - On stack async script:
Consider another case where we have the following:
Carousel may rely on library to load its resources, but there aren’t any guarantees that it’d be there. So it may be in the stack, but not a blocker (in the sense that we may lose the race and end up with a JS error)
As presented in examples above , there are possibilities of having multiple scripts that influence a particular resource (script). These influencer scripts can be on stack or even off the stack in certain cases, where they block the execution of the current script.
Questions
So we’d like to ask the community:
Single Initiator vs. Comprehensive Blocker List:
Handling "On Stack Async Script" Complexity:
Would appreciate your feedback and insights on this matter :)