Skip to content
This repository has been archived by the owner on Dec 5, 2022. It is now read-only.

Latest commit

 

History

History
193 lines (147 loc) · 7.92 KB

Performance.md

File metadata and controls

193 lines (147 loc) · 7.92 KB

Performance

Table of Contents

Introduction

With the help of front end hooks, we can easily analyze the performance and report the data to our backend server for monitoring.

Measuring fragment Initialization cost

By using the API hooks and with the help of User Timing API, We can easily measure the initialization time of all the fragments on the page.

page.html

<!doctype html>
<html>
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta charset="utf-8">
    <script>
        // mark before the fragment Init Start
        Pipe.onBeforeInit(function(attributes) {
            var fragmentId = attributes.id;
            performance.mark(fragmentId);
        });
        // Mark the fragment after it is initialized
        Pipe.onAfterInit(function(attributes) {
            var fragmentId = attributes.id;
            performance.mark(fragmentId + 'end');
            // Measure the time difference between mark start and mark end to get the initialization cost
            performance.measure('fragment-' + fragmentId, fragmentId, fragmentId + 'end');
        });
    </script>
</head>
<body>
    <!-- Measure till the header fragment is initialized -->
    <fragment id="header" src="http://header.zalando.de"/>
    <!-- Primary fragment -->
    <fragment primary id="product" src="http://product.zalando.de" />
    <fragment id="footer" src="http://footer.zalando.de" />
</body>
</html>

The metrics are shown visually on the Browser's timeline graph.

Fragment Initialization

We can collect the measured data using the Performance Timing API

var data = performance.getEntriesByType('measure');
// Output
[
    {
        duration: 0.370,
        entryType: "measure",
        name: "fragment-header",
        startTime: 419.95
    },
    {
        duration: 0.609,
        entryType: "measure",
        name: "fragment-product",
        startTime: 435.02
    },
    {
        duration: 0.299,
        entryType: "measure",
        name: "fragment-footer",
        startTime: 437.99
    },
]

By using the above data, its easier to do keep budgets for each fragment and even plot real time graphs for analysing the performance over time.

Measuring Time to interactive of critical content

The idea is heavily inspired by Time to interactive document. The measurement is however not the real Time to interative explained in the document but instead can be used as a proxy.

In order to measure the interactivity of the critical content, we need to agree on a set/group of fragments that can decide the page interactivity and also help in measuring the time taken for the same.

How its measured

Time to interactive of critical content seeks to identify the time when the JavaScript from the critical fragments(group of fragments) of the page gets initialized(compiled + parsed + executed) and the page is visually ready or meaningful. It is the difference between the marked time and the browser's navigation start.

If any of the critical fragments is rendered lazily, then interactive time would take the lazy rendering into account.

Clustering fragments

To cluster the fragments, we are going to add a new attribute timing-groups to the fragments tag on the page.

Note: Its totally possible to use different attribute name as well instead of timing-groups

The interactivity of the example Productpage is decided by Header, Product and Footer fragments and above the fold time is decided by Header and Product fragment.

Now to measure the time, We are going to use the hooks that are provided by Tailor.

ProductPage.html

<!doctype html>
<html>
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta charset="utf-8">
    <script>
        // Check the full implementation details in the example - https://github.com/zalando/tailor/tree/master/examples/fragment-performance/index.html
    </script>
</head>
<body>
    <fragment timing-groups="interactive,abovethefold" id="header" src="http://header.zalando.de"/>
    <fragment timing-groups="interactive,abovethefold" primary id="product" src="http://product.zalando.de" />
    <fragment timing-groups="reco-init" id="recos" src="http://recos.zalando.de" />
    <fragment timing-groups="interactive" id="footer" src="http://footer.zalando.de" />
</body>
</html>

Interativity

Please use the drop in replacement script here which measures both the fragment initialization as well the timing groups.

Custom metrics

Fragment development teams can add custom metrics that looks similar to PerformanceEntry that can be retrieved via tailor in addition to the hooks it supports.

Pipe.addPerfEntry("time-to-meaningful-paint", 2000.00) // done from some fragment on some page

Pipe.getEntries()
// returns [{
   name: "time-to-meaningful-paint",
   duration: 2000.00,
   entryType: "tailor",
   startTime: // start time relative to navigation start
}]

Why?

Browsers right now does not expose an API for creating custom PerformanceEntry and make them available on PerformanceTimeline.

why not perfomance.measure(User Timing)?

  • User Timing - with mark and measure there is no way to pass custom timing information and have the information as part of the PerformanceEntry object.

why not extend PerformanceEntry?

Even if we hack and extend the PerformanceEntry object, there is no way to retrive the custom entries that are added.

var customEntry = {};
customEntry.prototype = PerformanceEntry;
customEntry.name = "ttfmp";
customEntry.duration = Number(paint); // custom paint timing
customEntry.entryType = "tailor";
customEntry.startTime = performance.now();


// retrive entries
performance.getEntries(); 
// returns []

Future

There is a existing issue and proposal in w3c web perf group on exposing the API. So once its landed, we can fallback to that or continue to use them for older browsers. Issue - w3c/charter-webperf#28 Proposal - https://docs.google.com/document/d/1_zm9JB-Ul_fOtAMnF6yBcmvNL3m4-k4ram4pdMIcIug/

Caveats

Is the main thread available to handle the user input

The short answer is NO. Inorder to keep the main thread free, the fragments that are present below the fold, not visible (tracking), non critical should make sure their initialization cost is <50-60ms.

We also measure the initialization cost of each fragment on the page, In the future we could also provide warnings/errors if they fall over the budget.