Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 22, 2020 04:44 pm GMT

How to Detect Idle Browser Tabs with JavaScript

In some cases, we can found ourselves doing lots of intensive, CPU hungry tasks while the users are interacting with our end products or applications.
Firing pollers, establishing WebSocket connections or even loading media like videos or images could become performance dreadlocks especially if these tasks are consuming resources while there is no need to. It's a really good and meaningful practice to release the main thread from unnecessary workloads or network requests while the users are not actively interacting with the interface. In another manner, in an industry where most hosting providers are introducing quota-based pricing models reducing the network request could also reduce the costs for running your application or services.

The Page Visibility API

All the modern web browsers have incorporated the Page Visibility API which allows us to detect when a browser tab is hidden, moreover, we can also register an event listener in order to detect signals upon visibility changing.

document.visibilityState

The document.visibilityState could either be visible while the page is in a foreground
tab of a non-minimized window or hidden while the page is not actually visible to the user.

We can directly access the document.visibilityState as:

console.log(document.visibilityState);// => It could be `visible` or `hidden`

visibilitychange Event

We also can easily detect changes in the visibility property using an event listener.

const onVisibilityChange = () => {  if (document.visibilityState === 'hidden') {    console.log('> The window is hidden.');  } else {    console.log('> The window is visible.');  }};document.addEventListener('visibilitychange', onVisibilityChange, false);

An Example with Polling

Consider a scenario where we are polling our API for updates and we want to avoid making unnecessary calls for idle users. A simplified example would look like this:

const poll = () => {  const interval = 1500;  let _poller = null;  const repeat = () => {    console.log(`~ Polling: ${Date.now()}.`);  };  return {    start: () => {      _poller = setInterval(repeat, interval);    },    stop: () => {      console.log('~ Poller stopped.');      clearInterval(_poller);    }  };};const poller = poll();poller.start();const onVisibilityChange = () => {  if (document.visibilityState === 'hidden') {    poller.stop();  } else {    poller.start();  }};document.addEventListener('visibilitychange', onVisibilityChange, false);

Asynchronously Loading in the Background

But sometimes we can accelerate our users' end experience by following the other way around. Instead of canceling all jobs and requests we can asynchronously load external dependencies or assets. In that way, users' end experience would be more "contentful" and rich when they come back.

Webpack

Using ES2015 dynamic imports proposal along with the appropriate Webpack configuration manifest we can easily load additional modules or assets in the background

let loaded = false;const onVisibilityChange = () => {  if (document.visibilityState === 'hidden') {    // Aggresively preload external assets ans scripts    if (loaded) {      return;    }    Promise.all([      import('./async.js'),      import('./another-async.js'),      import(/* webpackChunkName: "bar-module" */ 'modules/bar'),      import(/* webpackPrefetch: 0 */ 'assets/images/foo.jpg')    ]).then(() => {      loaded = true;    });  }};document.addEventListener('visibilitychange', onVisibilityChange, false);

Rollup

Rollup does also support dynamic import out of the box.

let loaded = false;const onVisibilityChange = () => {  if (document.visibilityState === 'hidden') {    // Aggresively preload external assets ans scripts    if (loaded) {      return;    }    Promise.all([      import('./modules.js').then(({default: DefaultExport, NamedExport}) => {        // do something with modules.      })    ]).then(() => {      loaded = true;    });  }};document.addEventListener('visibilitychange', onVisibilityChange, false);

Preload with Javascript

Besides using a bundler we can also preload static assets like images using just a few lines of JavaScript.

let loaded = false;const preloadImgs = (...imgs) => {  const images = [];  imgs.map(    url =>      new Promise((resolve, reject) => {        images[i] = new Image();        images[i].src = url;        img.onload = () => resolve();        img.onerror = () => reject();      })  );};const onVisibilityChange = () => {  if (document.visibilityState === 'hidden') {    // Aggresively preload external assets ans scripts    if (loaded) {      return;    }    Promise.all(      preloadImgs(        'https://example.com/foo.jpg',        'https://example.com/qux.jpg',        'https://example.com/bar.jpg'      )    )      .then(() => {        loaded = true;      })      .catch(() => {        console.log('> Snap.');      });  }};document.addEventListener('visibilitychange', onVisibilityChange, false);

Micro-interactions

Finally, a neat approach for grabbing users' attention is dynamically changing the favicon, using just a few pixels you can retain interaction.

const onVisibilityChange = () => {  const favicon = document.querySelector('[rel="shortcut icon"]');  if (document.visibilityState === 'hidden') {    favicon.href = '/come-back.png';  } else {    favicon.href = '/example.png';  }};document.addEventListener('visibilitychange', onVisibilityChange, false);

References

You can also find this post on vorillaz.com


Original Link: https://dev.to/vorillaz/how-to-detect-idle-browser-tabs-with-javascript-88n

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To