Browser API Blitz

Mitch Keenan

Preface: Performance Observer

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    console.log(entry);
  }
});

observer.observe({ entryTypes: [ // These are all PerformanceEntry
  'frame', // Event Loop
  'navigation' // Navigation Events (slide XXX) 
  'resource' // Resource Requests
  'mark', 'measure', // User Timings API (slide XXX)
  'paint', // Paint Timing API (slide 4)
]});

We won't cover all of these but they are all useful, check them out.

Paint Timing API

// Put the following in `<head>`
const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    // `name` will be either 'first-paint' or 'first-contentful-paint'.
    const metricName = entry.name;

    // Adding startTime is important here or you could skew the numbers drastically.
    const time = Math.round(entry.startTime + entry.duration);

    console.log('Performance Metrics', metricName, time);
  }
});
observer.observe({ entryTypes: ['paint'] });
> Performance Metrics first-paint 1607
> Performance Metrics first-contentful-paint 1607

Intesection Observer API

const observer = new IntersectionObserver( entries => {
  entries.forEach( entry => {
    if ( entry.intersectionRatio > 0 ) {
      console.log('Entry is visible.');
    } else {
      console.log('Entry is not visible.');
    }
  });
});

observer.observe( document.querySelectorAll('.some-elements') );

Demo on Alligator.io

Media Capabilities API

const mediaConfig = {
  type: 'file',
  audio: {
    contentType: 'audio/ogg',
    channels: 2,
    bitrate: 132700,
    samplerateL: 5200
  }
};

navigator.mediaCapabilities.decodingInfo(mediaConfig).then(result => {
  console.log(result);
})
MediaCapabilitiesInfo {
  supported: false,
  smooth: false,
  powerEfficient: false
}

Network Info API

console.log(navigator.connection);
NetworkInformation {
  downlink: 10,
  effectiveType: '4g',
  onchange: null,
  rtt: 100,
  saveData: false,
}

Battery Status API [Deprecated]

if (navigator.battery) {
  console.log(navigator.battery);
} else if (navigator.getBattery) {
  navigator.getBattery().then(console.log);
} else {
  console.log('Battery Status not supported');
}
BatteryManager {
  charging: true,
  chargingTime: 0,
  dischargingTime: Infinity,
  level: 1,
  onchargingchange: null,
  onchargingtimechange: null,
  ondischargingtimechange: null,
  onlevelchange: null
}

Demo

Server Timing API

const entries = performance.getEntriesByType('resource');
console.log(entries[0].serverTiming);

In this case the server would be setting the following header:

Server-Timing: cache;desc="Cache Read";dur=23.2,db;dur=53,app;dur=47.2

And on the client we'd see the following log:

// Logs:
[
  PerformanceServerTiming { name: 'cache', duration: 23.2, description: 'Cache Read' },
  PerformanceServerTiming { name: 'db',    duration: 53,   description: '' },
  PerformanceServerTiming { name: 'app',   duration: 47.2, description: '' }
]

Long Task API

Note: Chrome only for now

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    console.log(entry);
  }
});
observer.observe({ entryTypes: ['longtask'] });

Demo

Others

Not oncluded in Henri's Presentation, but I think are relevant.

Navigation Timing API

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    console.log(entry);
  }
});
observer.observe({ entryTypes: ['navigation'] });
// Logs:
PerformanceNavigationTiming {
  connectEnd: 14.800000004470348,
  connectStart: 14.600000009522773,
  decodedBodySize: 50817,
  domComplete: 2621.500000008382,
  domContentLoadedEventEnd: 799.299999998766,
  domContentLoadedEventStart: 785.7000000076368,
  domInteractive: 782.2000000014668,
  domainLookupEnd: 14.600000009522773,
  domainLookupStart: 14.600000009522773,
  duration: 2653.7000000098487,
  encodedBodySize: 50817,
  // ... 20 more
}

Timers 1: time and timeEnd

const TIMER_NAME = 'myFirstTimer';

console.time(TIMER_NAME); // Start the timer

setTimeout(() => {
  console.timeEnd(TIMER_NAME); // End the timer and log the elapsed time.
}, 1000);
// Logs:
> myFirstTimer: 1002.4091796875ms

Timers 2: performance.now()

const t1 = performance.now();

setTimeout(() => {
  const t2 = performance.now();
  
  console.log(`Took ${t2 - t1} milliseconds.`);
}, 1000);
// Logs:
> Took 1001.7000000079861 milliseconds.

Timers 3: User Timing API

performance.mark('start-script'); // Create Starting Mark
setTimeout(() => {
  performance.mark('end-script'); // Create Ending Mark
  
  // Create the Measure
  performance.measure('total-time', 'start-script', 'end-script');

  // Get the result
  const result = performance.getEntriesByName('total-time', 'measure')[0];

  console.log(result);
}, 1000);
// Logs:
PerformanceMeasure {
  name: 'total-script-execution-time',
  entryType: 'measure',
  startTime: 4354.699999996228,
  duration: 1004.2000000103144
}

We Made It!