Measure network performance by resource timing API
Recently, we have been working on improving our web performance by setting up CDN (Content Delivery Networks) in mainland China. We used to rely on AWS CloudFront to deliver our static data worldwide. However, the network infrastructure is so complex in China, and there are no edge locations currently available inside of it. Thus, we have to leverage against local CDN providers to make sure our users in China have the same network latency and throughput as people outside of it. The question is how well it performs compared to AWS CloudFront.
This article will focus on what resource timing API is and how to use it to measure the network performance. In the end, we will give some key points we wish we knew when we get started. Before we get into it, we should let you know there are some pretty cool services like Webpagetest, ThousandEyes that aim to provide timing metrics of network performance or benchmark for CDN providers. But, we think it will be more interesting if we can collect real world data from our users.
Resource loading phases
Let’s start with resource loading phases. The figure above gives us a clear picture about what stages browser has to go through when it fetches the resource.
If there are HTTP redirects when fetching the resource, otherwise, the length of redirect time is 0.
Resources may be cached in browser for later use or offline support. If the resource can be obtained from cache, it will jump over the next 2 phases and go to the “Request” phase.
In this phase, the browser will start the domain name lookup. The domain name like “www.google.com” will be mapped to an IP address in this phase. If the browser has the domain information in cache, it can retrieve from that and the length of DNS lookup time will be 0.
In this phase, the browser starts to establish the TCP connection, aka three-way handshake, with the server to get the resource. To open a new TCP connection for every request/response is not efficient. A single TCP connection once established can be reused to send multiple requests/responses. If a persistent connection is reused, the length of TCP connection time is 0.
If SSL handshake is required, it will be included in this phase as well.
The browser starts to send request to the server.
This phase begins right at the time the browser receives the first byte of the response from the server or local cache, ends immediately after receiving the last byte.
Resource Timing API
var resources =
resources is an array of
PerformanceResourceTiming objects. The
PerformanceResourceTiming object contains the URL of the requested resource, timing metrics and resource size data. The browser has a resource timing buffer to hold
PerformanceResourceTiming objects. Whenever the browser starts to fetch a resource, it will create a new
PerformanceResourceTiming object and store into the buffer until the buffer is full.
With the help of the properties of resource timing, you can calculate the amount of time the resource loading phases take.
redirectEnd — redirectStart
- DNS lookup:
domainLookupEnd — domainLookupStart
- TCP handshake:
connectEnd — connectStart
responseEnd — responseStart
The following example illustrates using these properties to calculate loading times.
Tips to use resource timing API
As you can see, it’s pretty easy to use resource timing API to measure the network performance. But when we wrote the script to do the calculation, there are some issues we thought it’s worth sharing.
Why the properties are 0?
For cross origin resources, the following properties are returned as 0 by default.
- redirectStart, redirectEnd
- domainLookupStart, domainLookupEnd
- connectStart, connectEnd, secureConnectionStart
If you see these properties are 0, don’t be too surprise, that’s because the resource’s domain doesn’t match your domain. To permit these values to be shared, server should have
Timing-Allow-Origin HTTP header with a value to tell browser what origins can get the timestamp value. You can specify
Timing-Allow-Origin: * to permit all origins to see the timing detail.
Can’t find the performance entry of the resource
When browser starts to fetch a resource, it will create a
PerformanceResourceTiming object to collect the timing metrics and put it into the resource timing buffer. However, the buffer is not unlimited. You have to manage the buffer size in case your application may use more entries than the limit.
clearResourceTimings() method to remove all the entries in the buffer and
setResourceTimingBufferSize() method to adjust the buffer limit. The
resourcetimingbufferfull event will be fired as well when the buffer is full. With the help of this event, you can set up an event handler to clear the entries when the buffer reaches its limit.
Wait, where is requestEnd?
As you see from the image of loading phases, the resource timing API does not include
requestEnd , which may represent the completion of sending the request. Let’s see how w3c explain it.
Completion of sending the request from the user agent does not always indicate the corresponding completion time in the network transport, which brings most of the benefit of having such an attribute.
Some user agents have high cost to determine the actual completion time of sending the request due to the HTTP layer encapsulation.
We were wondering the time elapsed between the completion of sending HTTP request and the time when the browser get the first byte. But, it seems like no way to get it.
Why some properties are gone?
Almost all modern browsers have supported the resource timing API, but some only include timing metrics without the resource size data. At this time, the mobile Safari is still not supporting yet. Please see the browser compatibility before using it.
What about the resources loaded within the iframe?
Only the iframe’s
src resource is included as an entry in the resource timing buffer. The sub-resources requested within the iframe can be found by using
The resource timing API can help you to measure the network performance of your application. You can use it to track the metrics of DNS lookup, TCP handshake, etc. We hope that you find this article interesting, and can help you to get started to use the resource timing API to collect the real world data of your website.