element timing methods

Benchmark created on


Preparation HTML

<div id="ui-paint-timing-container"></div>
<pre id="log"></pre>

Setup

const container = document.getElementById('ui-paint-timing-container');
const logEl = document.getElementById('log');

function log(msg) {
  console.log(msg);
  logEl.textContent += msg + '\n';
}

const transparentPngDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';

const hiddenStyle = {
  position: 'fixed',
  top: '0',
  left: '0',
  userSelect: 'none',
  overflow: 'hidden',
  zIndex: '-1',
  pointerEvents: 'none',
};

let counter = 0;

log('Element timing supported: ' + PerformanceObserver.supportedEntryTypes?.includes('element'));

function createTextElement(id) {
  const element = document.createElement('span');
  element.innerText = '.';
  element.setAttribute('elementtiming', id);
  Object.assign(element.style, hiddenStyle, { fontSize: '1px' });
  return element;
}

function createImageElement(id) {
  const element = document.createElement('img');
  element.src = transparentPngDataUri;
  element.width = 1;
  element.height = 1;
  element.setAttribute('elementtiming', id);
  Object.assign(element.style, hiddenStyle);
  return element;
}

function observeElementTiming(createEl, deferred) {
  const id = 'el-' + counter++;
  const startTime = performance.now();
  const element = createEl(id);
  log(`[${id}] Created ${element.tagName} at ${startTime.toFixed(2)}ms`);
  
  const timeout = setTimeout(() => {
    const elapsed = performance.now() - startTime;
    log(`[${id}] TIMEOUT after ${elapsed.toFixed(2)}ms`);
    observer.disconnect();
    container.removeChild(element);
    deferred.resolve();
  }, 5000);
  
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (entry.identifier === id) {
        const elapsed = performance.now() - startTime;
        log(`[${id}] ${element.tagName} resolved in ${elapsed.toFixed(2)}ms (renderTime=${entry.renderTime.toFixed(2)})`);
        clearTimeout(timeout);
        observer.disconnect();
        container.removeChild(element);
        deferred.resolve();
        return;
      }
    }
  });
  
  observer.observe({ type: 'element', buffered: false });
  container.appendChild(element);
}

Test runner

Ready to run.

Testing in
TestOps/sec
text (span)
observeElementTiming(createTextElement, deferred);
ready
img (base64)
observeElementTiming(createImageElement, deferred);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.