JavaScript

Loading Priorities

Adaptive Loading

&

Why this talk?

Web

Performance

Product

Web Almanac

JavaScript

Web Almanac

JavaScript

Web Almanac

JavaScript

Web Almanac

JavaScript

Web Almanac

JavaScript

Web Almanac

JavaScript

JavaScript

Adaptive Loading

 @media (min-width: 50em) {
   article {
     column-count: 2;
   }
 }
<img 
  srcset="image-wide.jpg 600w,
          image-ultrawide.jpg 1200w"
  sizes="(min-width: 600px) 600w,
         (min-width: 1200px) 1200w"
  src="image.jpg"
  height="300"
  width="200"
  alt="Awesome image">

 window
  .matchMedia('(min-width: 768px)')
  .matches
import { useMediaQuery } from 'usehooks-ts'

export default function Component() {
  const matches = useMediaQuery('(min-width: 768px)')

  return (
    <div>
      {`The view port is 
		${matches ? 'at least' : 'less than'} 
    	768 pixels wide`}
    </div>
  )
}
import { useEffect, useState } from 'react'

function useMediaQuery(query: string): boolean {
  const getMatches = (query: string): boolean => {
    // Prevents SSR issues
    if (typeof window !== 'undefined') {
      return window.matchMedia(query).matches
    }
    return false
  }

  const [matches, setMatches] = useState<boolean>(getMatches(query))

  function handleChange() {
    setMatches(getMatches(query))
  }

  useEffect(() => {
    const matchMedia = window.matchMedia(query)

    // Triggered at the first client-side load and if query changes
    handleChange()

    // Listen matchMedia
    if (matchMedia.addListener) {
      matchMedia.addListener(handleChange)
    } else {
      matchMedia.addEventListener('change', handleChange)
    }

    return () => {
      if (matchMedia.removeListener) {
        matchMedia.removeListener(handleChange)
      } else {
        matchMedia.removeEventListener('change', handleChange)
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [query])

  return matches
}

export default useMediaQuery

This property is used to leverage the user's Data Saver preferences.

This property is used to fine-tune data transfer to use less bandwidth.

This property is the CPU core count. It is used to limit costly JavaScript execution and reduce CPU intensive logic when a device can't handle it well.

This property is used to reduce memory consumption on low-end devices.

Navigator & NetworkInformation APIs

Navigator & NetworkInformation APIs

Navigator & NetworkInformation APIs

export default function WebVitalsReporter({...}) {
  ...
  
  useMount(() => {
    const {
      deviceMemory,
      connection: {effectiveType} = {},
      hardwareConcurrency
    } = window.navigator || {}
    
    const handleAllChanges = ({attribution, name, rating, value}) => {
      ...

      logger.cwv({
        ...
        ...(deviceMemory && {deviceMemory}),
        ...(effectiveType && {effectiveType}),
        ...(hardwareConcurrency && {hardwareConcurrency})
      })
    }
  }
  
}

| Last 7 days

// In the browser
const isSaveDataEnabled = () => {
  return navigator.connection?.saveData ?? false;
};

// Use Case
if (isSaveDataEnabled()) {
  // Load light component
  await import('./LightweightComponent');
} else {
  // Load default component
  await import('./FullComponent');
}

saveData example

import { useNetworkStatus } from 'react-adaptive-hooks/network';
import { useSaveData } from 'react-adaptive-hooks/save-data';
import { useHardwareConcurrency } from 'react-adaptive-hooks/hardware-concurrency';
import { useMemoryStatus } from 'react-adaptive-hooks/memory';
import { useMediaCapabilitiesDecodingInfo } from 'react-adaptive-hooks/media-capabilities';
import React from 'react';

import { useNetworkStatus } from 'react-adaptive-hooks/network';

const MyComponent = () => {
  const { effectiveConnectionType } = useNetworkStatus();

  let media;
  switch(effectiveConnectionType) {
    case 'slow-2g':
      media = <img src='...' alt='low resolution' />;
      break;
    case '2g':
      media = <img src='...' alt='medium resolution' />;
      break;
    case '3g':
      media = <img src='...' alt='high resolution' />;
      break;
    case '4g':
      media = <video muted controls>...</video>;
      break;
    default:
      media = <video muted controls>...</video>;
      break;
  }
  
  return <div>{media}</div>;
};
import type { EffectiveConnectionType } from '@sbt-web/hooks';

interface Hooks {
  saveData?: boolean | null;
  effectiveConnectionType?: EffectiveConnectionType | null;
  deviceMemory?: number | null;
}

const shouldReduceDataUse = ({
  saveData = null,
  effectiveConnectionType = null,
  deviceMemory = null,
}: Hooks): boolean => {
  const saveDataSignal = saveData ?? false;
  const ectSignal = effectiveConnectionType ?? '4g';
  const deviceMemorySignal = deviceMemory ?? Infinity;

  return saveDataSignal || ectSignal !== '4g' || deviceMemorySignal <= 2;
};

export default shouldReduceDataUse;
import VueAdaptiveNetwork from 'vue-adaptive-components/network';
import VueAdaptiveSaveData from 'vue-adaptive-components/save-data';
import VueAdaptiveMemory from 'vue-adaptive-components/hardware-concurrency';
import VueAdaptiveHardwareConcurrency from 'vue-adaptive-components/memory';
<template>
  <vue-adaptive-network>
    <template v-slot="{ effectiveConnectionType }">
      <img v-if="effectiveConnectionType === 'slow-2g'" src='...' alt='low resolution' />
      <img v-else-if="effectiveConnectionType === '2g'" src='...' alt='medium resolution' />
      <img v-else-if="effectiveConnectionType === '3g'" src='...' alt='high resolution' />
      <video v-else-if="effectiveConnectionType === '4g'" muted="" controls="">...</video>
      <video v-else="" muted="" controls="">...</video>
    </template>
  </vue-adaptive-network>
</template>

<script>
import VueAdaptiveNetwork from 'vue-adaptive-components/network'

export default {
  components: {
    VueAdaptiveNetwork
  }
}
</script>

JavaScript

Loading Priorities

preload
prefetch
preconnect
dns-prefetch
prerender
modulepreload

speculationrules

DEPRECATED

<head>
  <link rel="preload" as="script" href="critical.js">
</head>
<link rel="preload" href="ComicSans.woff2" as="font" type="font/woff2" crossorigin>
Link: </css/style.css>; rel="preload"; as="style"
import(_/* webpackPreload: true */_ "CriticalChunk")

Preload critical assets

</>

</>

<script src="script.js">
  
<script async src="script.js">

<script defer src="script.js">
  
<script type="module" src="module.mjs">

<script>, async, defer, module

<script>, async, defer, module

async & defer


<script async
        defer
        src="script.js">
  

Desktop 28%

Mobile 29%

Speculation Rules API

<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["next.html", "next2.html"]
    }
  ]
}
</script>

Speculation Rules API

Speculation Rules API

Barry Pollard

Key Takeaways

Know and use the platform

User centric

Data Driven

Know how browser works

JavaScript Loading Priorities and Adaptive Loading | GDG Valencia 2024

By Joan León

JavaScript Loading Priorities and Adaptive Loading | GDG Valencia 2024

First, we will talk about adaptive loading, an essential technique in today's online world. Adaptive loading allows your website to adapt to different devices and internet capabilities, ensuring that users don't have to deal with extremely long loading times or performance issues. We will discuss techniques such as image optimization, progressive loading, and methods for evaluating site loading speed on different devices. Next, we will move on to resource loading prioritization, a technique that can truly make a difference in site performance. We will explore how the browser loads resources of a website and how HTML tags can be used to specify the loading priority of each resource. We will also share practical techniques such as loading custom fonts and deferred JavaScript to implement prioritized resource loading. By the end of the talk, you will have the knowledge to apply these techniques to your own projects and take user experience and site performance to the next level. So get ready to enhance your web development skills and create even more impressive websites!

  • 288