Skip to main content




Modify the assets offered to users based on the conditions of their device and network.


Updated

It appears in:
Network reliability

Los usuarios acceden a sitios Web a través de una amplia variedad de dispositivos y conexiones de red. Incluso en las principales ciudades, donde las redes móviles son rápidas y confiables, uno puede terminar experimentando tiempos de carga más lentos, por ejemplo, al viajar en el metro, en un automóvil o simplemente al moverse. En regiones como los mercados emergentes, este fenómeno es aún más común, no solo debido a redes poco confiables, sino también porque los dispositivos tienden a tener menos memoria y potencia de procesamiento de CPU.

La carga adaptable es un patrón de rendimiento web que le permite adaptar su sitio en función de la red del Username y las condiciones del dispositivo.

The adaptive load pattern is made possible by service workers, the Network Information API, the Hardware Concurrency API, and the Device memory API. En esta guía, exploramos cómo puede utilizar los trabajadores del servicio y la API de información de red para lograr una strategy de carga adaptable.

Production case

Terra is one of the largest media companies in Brazil. It has a large user base, coming from a wide variety of devices and networks.

To provide a more reliable experience for all of its users, Terra combines service workers and Network Information API to offer lower quality images to users on 2G or 3G connections.

terra-adaptive-images-3516746

La empresa también descubrió que los scripts y los activos (como los banners) cargados por las redes publicitarias eran especialmente perjudiciales para los usuarios que navegaban en 3G o conexiones más lentas.

As is the case with many publishers, Terra serves AMP versiones de sus páginas a usuarios procedentes de search engines y otras plataformas de link exchange. Las páginas AMP suelen ser livianas y ayudan a mitigar el impacto de los anuncios en el rendimiento al reducir la prioridad de su carga con respecto al contents principal de la página.

With this in mind, Terra decided to start offering AMP versions of its pages not only to users coming from search engines, but also to those browsing its site on 3G or slower connections.

To achieve this, they use the Network Information API en el trabajador del servicio para detectar si la solicitud proviene de 3G o más lento. Si ese es el caso, cambian la Url de la página para solicitar la versión AMP de la página.

terra-adaptive-amp-9466834

Thanks to this technique, they send 70% fewer bytes to users with slower connections. the time used on AMP pages is higher for 3G users and ads on AMP pages have a better CTR (clickthrough rate) for that group.

Implement adaptive loading with Workbox

In this section, we will explore how Workbox can be used to implement adaptive loading strategies.

Workbox proporciona varias estrategias de almacenamiento en cache en tiempo de ejecución listas para usar. Se utilizan para indicar cómo el trabajador del servicio genera una respuesta después de recibir una fetch event.

For example, in a Cache first strategy the Request it will be fulfilled using the cached response (if available). If there is no cached answer, Request it will be fulfilled by a network request and the response will be cached.

import {registerRoute} desde 'workbox-routing';
import {CacheFirst} desde 'workbox-strategies';

registerRoute(
new RegExp('/img/'),
new CacheFirst()
);

Caching strategies can be customized with Workbox Plugins. These allow you to add additional behaviors by manipulating requests and responses during the life cycle of a request. Workbox has several built-in plugins for common cases and APIs, but you can also define a custom pluginand enter some custom logic of your choice.

To achieve load adaptation, define a custom plugin, called, for example, adaptiveLoadingPlugin:

const adaptiveLoadingPlugin = {
requestWillFetch: async ({request}) => {
const urlParts = request.url.split('/');
let imageQuality;

switch (
navigator && navigator.connection
? navigator.connection.effectiveType
: ''
) {
case '3g':
imageQuality = 'q_30';
break;
}

const newUrl = urlParts
.splice(urlParts.length - 1, 0, imageQuality)
.join('/')
.replace('.jpg', '.png');
const newRequest = new Request(newUrl.href, {headers: request.headers});

return newRequest;
},
};

The above code does the following:

  • Implement a requestWillFetch () callback: called every time a network request is to be made, so you can modify the Request.
  • Check the type of connection, using the Network Information API. Based on the state of the network, it creates a new URL part, which indicates the quality of the image to be searched (eg. q_30 for 3G users).
  • Create a new URL based on dynamics newPart value and returns the new Request to perform, based on that URL.

Then pass the complement to a cacheFirst strategy that contains a regular expression to match the image urls (ex. / img /):

workbox.routing.registerRoute(
new RegExp('/img/'),
workbox.strategies.cacheFirst({
cacheName: 'images',
plugins: [
adaptiveLoadingPlugin,
workbox.expiration.Plugin({
maxEntries: 50,
purgeOnQuotaError: true,
}),
],
}),
);

As a result, when image requests are intercepted, the runtime caching strategy will try to satisfy the request from the cache. If not available, it will run logic in the plugin to decide what image quality to retrieve from the network.

Finally, the response will be cached and sent back to the page.

Cloudinary Workbox Plugin

Cloudinary, an image and video hosting service, has Workbox Plugin which encapsulates the functionality explained in the previous section, making it even easier to implement.

cloudinary-workbox-5686987

The plugin is designed to work with Workbox Web Pack Plugin. To implement it, use the GenerateSW () class:

new workboxPlugin.GenerateSW({
swDest: 'sw.js',
importScripts: ['./cloudinaryPlugin.js'],
runtimeCaching: [
{
urlPattern: new RegExp('^https://res.cloudinary.com/.*/image/upload/'),
handler: 'CacheFirst',
options: {
cacheName: 'cloudinary-images',
plugins: [
{
requestWillFetch: async ({request}) =>
cloudinaryPlugin.requestWillFetch(request),
},
],
},
},
],
});

The above code does the following:

  • Use the GenerateSW () class to configure webpack to generate a service worker on the target indicated in swDest.
  • Import the cloudinary plugin script.
  • Defines a Cache First runtime caching strategy for image requests to Cloudinary CDN.
  • Pass the Cloudinary Workbox Plugin to adjust the image quality according to network conditions.

Explore more adaptable charging strategies

You can go further by mapping device signals, such as hardware concurrency and Memory device to device categories and then offer different assets based on device type (low-end, mid-range, or high-end).