Skip to content

Latest commit

 

History

History
251 lines (208 loc) · 8.21 KB

js-snippets.md

File metadata and controls

251 lines (208 loc) · 8.21 KB

Awesome JavaScript Snippets

Animation

// Double RAF is useful for ensuring that animations start before expensive rendering is done.
// It helps provide smoother user experience by making animations feel reactive.
// Normal rendering would block the animation from starting.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#animation
// ES6
const doubleRAF = cb => requestAnimationFrame(() => requestAnimationFrame(cb));

// ES7
const requestAnimationFramePromise = () => new Promise(resolve => requestAnimationFrame(resolve));
const doubleRAF = async () => { 
  await requestAnimationFramePromise();
  await requestAnimationFramePromise();
};

// Examples
// With double RAF as shown here the rendering function safely runs in the main thread
// after the animation has already started.
// ES6
button.addEventListener('click', function() {
  element.classList.add('animating');
  doubleRAF(renderNextView);
});

// ES7
element.classList.add('animating');
await doubleRAF();
renderNextView();

source, source2, source3

Document

// Clear a focus.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#document
document.activeElement.blur();

source

Network

// Don't run if the user is on 2G or if Save-Data is enabled.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#network
if (conn = navigator.connection) {
  if ((conn.effectiveType || '').includes('2g') || conn.saveData) return;
}

source

Optimization

// Defer another network requests after initial frame is rendered to keep the page load performant.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#optimization
const defer = fn => {
  const raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
              window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
  if (raf) raf(() => window.setTimeout(fn, 0));
  else window.addEventListener('load', fn);
}

const deferScript = scriptUrl => {
  defer(() => {
    const script = document.createElement('script');
    script.async = true;
    script.src = scriptUrl;
    document.body.appendChild(script);
  });
}

const deferStyles = noscriptId => {
  defer(() => {
    const addStylesNode = document.getElementById(noscriptId);
    const replacement = document.createElement('div');
    replacement.innerHTML = addStylesNode.textContent;
    document.body.appendChild(replacement);
    addStylesNode.parentElement.removeChild(addStylesNode);
  });
}

// Examples
deferScript('https://www.google-analytics.com/analytics.js');

// Check that service workers are registered.
if ('serviceWorker' in navigator) {
  defer(() => navigator.serviceWorker.register('/sw.js'));
}

<noscript id="deferred-styles">
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:500&subset=latin-ext">
</noscript>
<script>
  deferStyles('deferred-styles');
</script>

source

Performance

// Polyfill/shim for the requestIdleCallback and cancelIdleCallback API.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#performance
window.requestIdleCallback = window.requestIdleCallback ||
  cb => {
    const start = Date.now();
    return setTimeout(() => {
      cb({
        didTimeout: false,
        timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
      });
    }, 1);
  };

window.cancelIdleCallback = window.cancelIdleCallback || id => clearTimeout(id);

source

// Get anytime a single task blocks the main thread for more than 50ms.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#performance
function sendLongTaskDataToGoogleAnalytics(entryList) {
  // Assumes the availability of requestIdleCallback (or a shim).
  requestIdleCallback(() => {
    for (const entry of entryList.getEntries()) {
      ga('send', 'event', {
        eventCategory: 'Performance Metrics',
        eventAction: 'longtask',
        eventValue: Math.round(entry.duration),
        eventLabel: JSON.stringify(entry.attribution),
      });
    }
  });
}

// Create a PerformanceObserver and start observing Long Tasks.
new PerformanceObserver(sendLongTaskDataToGoogleAnalytics).observe({
  entryTypes: ['longtask'],
});

source

// Using requestIdleCallback for sending analytics data.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#performance
const processPendingAnalyticsEvents = deadline => {
  // Reset the boolean so future rICs can be set.
  isRequestIdleCallbackScheduled = false;

  // If there is no deadline, just run as long as necessary.
  // This will be the case if requestIdleCallback doesn’t exist.
  if (typeof deadline === 'undefined')
    deadline = { timeRemaining: () => Number.MAX_VALUE };

  // Go for as long as there is time remaining and work to do.
  while (deadline.timeRemaining() > 0 && eventsToSend.length > 0) {
    var evt = eventsToSend.pop();
    ga('send', 'event',
        evt.category,
        evt.action,
        evt.label,
        evt.value);
  }

  // Check if there are more events still to send.
  if (eventsToSend.length > 0) schedulePendingEvents();
}

const schedulePendingEvents = () => {
  // Only schedule the rIC if one has not already been set.
  if (isRequestIdleCallbackScheduled) return;

  isRequestIdleCallbackScheduled = true;

  // Assumes the availability of requestIdleCallback (or a shim).
  // Wait at most two seconds before processing events.
  requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 });
}

let eventsToSend = [];
let isRequestIdleCallbackScheduled = false;

// Example
function onNavOpenClick () {
  // Animate the menu.
  menu.classList.add('open');

  // Store the event for later.
  eventsToSend.push(
    {
      category: 'button',
      action: 'click',
      label: 'nav',
      value: 'open'
    });

  schedulePendingEvents();
}

source

Prefetching for subsequent pages

Safari

Time

// Fastest method to get timestamp.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#time
const timestamp = Date.now();

source

// Timestamp in milliseconds.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#time
const timestampInMs = window.performance && window.performance.now && window.performance.timing &&
                      window.performance.timing.navigationStart ?
                      window.performance.now() + window.performance.timing.navigationStart : Date.now();

source

URL

// Remove URL parameters without refreshing page.
// https://github.com/UseWebPlatform/awesome-web-platform/js-snippets.md#url
window.history.replaceState(null, null, window.location.pathname);

source

Another snippets