Superpowers of browser's Web API  

Web API

console.log(1);
setTimeout(() => console.log(2), 0);
console.log(3);

?

Web API

Collection of built-in interfaces that allow developers to interact with and manipulate web pages and web applications within a web browser.

- Web API docs

Web API

Nikola Mitrović

Development Lead & Technical Architect

Vega IT

Novi Sad, Serbia

Tech Speaker

Intersection Observer API

  • Provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport

import { useState, useEffect, RefObject } from 'react';

export const useVisible = (
  ref: RefObject<HTMLDivElement>,
  options = {
    root: null,
    rootMargin: '0px',
    threshold: 1.0
  }
) => {
  const [isVisible, setIsVisible] = useState<boolean>(false);

  useEffect(() => {
    const { current: elementRef } = ref;
    
    if (elementRef) {
      const observer = new IntersectionObserver(
        ([entry]) => setIsVisible(entry.isIntersecting), options
      );

      observer.observe(elementRef);

      return () => observer.unobserve(elementRef);
    }
  }, [ref, options]);

  return isVisible;
};

Intersection Observer API

Lazy-load images

Infinite scroll lists

Defer animations

Save compute power

03

02

04

01

Intersection Observer API - Use Cases

Intersection Observer API - Browser Support

Page Visibility API

  • Provides events you can watch for to know the current visibility state of the page

  • Triggers when user

switches tab

minimizes window

puts another window as overlay

locks/turns off device

Page Visibility API

import { useEffect, useState } from "react";

export const usePageVisibility = () => {
  const [pageVisible, setPageVisible] = useState<boolean>(true);

  useEffect(() => {
    const handleVisibilityChange = () => {
      const isPageVisible = document.visibilityState === "visible";
      setPageVisible(isPageVisible);
    };

    document.addEventListener("visibilitychange", handleVisibilityChange);

    return () => {
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, []);

  return pageVisible;
};

Page Visibility API - Use Cases

Improving performance

01

Pause audio/video

02

Detect page visit count

03

Poll server data

04

Carousel

05

Page Visibility API - Browser Support

Screen Wake Lock API

  • Prevent devices from locking the screen when an application needs to keep running

  • Only visible (active) documents can acquire the screen wake lock

Screen Wake Lock API

import { useEffect, useCallback, useRef } from 'react';

export const useWakeLock = (shouldWakeLock = false) => {
  let sentinel = useRef<WakeLockSentinel | null>(null);

  const requestWakeLockSentinel = useCallback(async () => {
    sentinel.current = await navigator.wakeLock.request('screen');
  }, []);

  const releaseWakeLockSentinel = useCallback(async () => {
    await sentinel.current?.release();
    sentinel.current = null;
  }, []);

  useEffect(() => {
    (async () => {
      if (shouldWakeLock) {
        await requestWakeLockSentinel();

        return releaseWakeLockSentinel;
      }

      await releaseWakeLockSentinel();
    })();
  }, [shouldWakeLock, requestWakeLockSentinel, releaseWakeLockSentinel]);

  return { isWakeLock: !!sentinel.current };
};

Screen Wake Lock API - Use Cases

Reading an ebook

Presenting to an audience

Following a recipe

Map navigation

Scanning a QR / barcode

03

05

02

04

01

Screen Wake Lock API - Browser Support

Screen Wake Lock API - Drawbacks

Network API

  • Provides information about the system's connection, such as the current bandwidth of the user's device or whether the connection is metered

  • Detect connection changes

 

import { useState, useEffect } from "react";

enum ENetworkEffectiveType {
  SLOW_TWO_G = "slow-2g",
  TWO_G = "2g",
  THREE_G = "3g",
  FOUR_G = "4g",
}

export const useNetwork = () => {
  const [isFastNetwork, setIsFastNetwork] = useState<boolean | null>(null);

  useEffect(() => {
    if ("connection" in navigator) {
      const { connection: { effectiveType } } = navigator;
      setIsFastNetwork(effectiveType === ENetworkEffectiveType.FOUR_G);
    }
  }, []);

  return isFastNetwork;
};

Network API

import { useState, useEffect } from "react";

enum ENetworkEffectiveType {
  SLOW_TWO_G = "slow-2g",
  TWO_G = "2g",
  THREE_G = "3g",
  FOUR_G = "4g",
}

export const useNetwork = () => {
  const [isFastNetwork, setIsFastNetwork] = useState<boolean | null>(null);
  
  const updateConnectionStatus = ({ target: { effectiveType } }: Event) => {
    setIsFastNetwork(effectiveType === ENetworkEffectiveType.FOUR_G);
  };

  useEffect(() => {
    if ("connection" in navigator) {
      const { effectiveType } = navigator.connection;
      setIsFastNetwork(effectiveType === ENetworkEffectiveType.FOUR_G);
      
      navigator.connection.addEventListener("change", updateConnectionStatus);
    }
  }, []);

  return isFastNetwork;
};

Network API

Network API - Use Cases

Notification to the user

Preload large resources

02

01

Network API - Browser Support

Background Sync API

  • Provides a way to defer tasks to be run in a service worker until the user has a stable network connection

Background Sync API

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}

Background Sync API

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}
self.addEventListener("sync", (event) => {
  if (event.tag === "sync-planets") {
    event.waitUntil(fetchPlanets());
  }
});

Background Sync API - Use Cases

Offline capabilities

Send email while offline

02

01

Background Sync API - Browser Support

Background Sync API

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}
self.addEventListener("sync", (event) => {
  if (event.tag === "sync-planets") {
    event.waitUntil(fetchPlanets());
  }
});

Background Sync API

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}
const fetchPlanets = async () => {
  const planetsResponse = await fetch(
    "https://exoplanetarchive.ipac.caltech.edu"
  );
  const planets = await planetsResponse.json();
};

self.addEventListener("sync", (event) => {
  if (event.tag === "sync-planets") {
    event.waitUntil(fetchPlanets());
  }
});

Broadcast Channel API

  • Allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin

  • Bi-directional communication

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}
const fetchPlanets = async () => {
  const planetsResponse = await fetch(
    "https://exoplanetarchive.ipac.caltech.edu"
  );
  const planets = await planetsResponse.json();
};

self.addEventListener("sync", (event) => {
  if (event.tag === "sync-planets") {
    event.waitUntil(fetchPlanets());
  }
});

Broadcast Channel API

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}
const broadcast = new BroadcastChannel("planets-channel");

const fetchPlanets = async () => {
  const planetsResponse = await fetch(
    "https://exoplanetarchive.ipac.caltech.edu"
  );
  const planets = await planetsResponse.json();
  
  broadcast.postMessage({ planets });
};

self.addEventListener("sync", (event) => {
  if (event.tag === "sync-planets") {
    event.waitUntil(fetchPlanets());
  }
});

Broadcast Channel API

import React from "react";
import { Link } from "react-router-dom";

export const FlightsLink = () => {
  useEffect(() => {
    const broadcast = new BroadcastChannel("planets-channel");

    broadcast.onmessage = ({ data: { planets } }) => setPlanets(planets);

    return () => broadcast.close();
  }, []);
  
  const registerPlanetsSync = async () => {
    const registration = await navigator.serviceWorker.ready;

    try {
      await registration.sync.register("sync-planets");
    } catch {
      console.log("Background Sync could not be registered!");
    }
  };

  return (
    <Link
      to="rocket"
      onMouseEnter={registerPlanetsSync}
    >
      EXPLORE
    </Link>  
  )
}
const broadcast = new BroadcastChannel("planets-channel");

const fetchPlanets = async () => {
  const planets = await fetch(
    "https://exoplanetarchive.ipac.caltech.edu"
  ).then((response) => response.json());
  
  broadcast.postMessage({ planets });
};

self.addEventListener("sync", (event) => {
  if (event.tag === "sync-planets") {
    event.waitUntil(fetchPlanets());
  }
});

Broadcast Channel API

Detect user action

Logout in all tabs

02

01

Broadcast Channel API - Use cases

Broadcast Channel API - Browser Support

Web API - Bonus points

  • Beacon API

  • Web Speech API

  • Web Share API

  • Background Fetch API

  • Notification API

  • Network API

  • WebRTC

  • Web Authn

Web API - Takeaways

Non-existing browser support

Experimental browser support

Device support

03

02

01

Backwards compability

04

Web API - Takeaways

Standardized code

Standardized code

Standardized code

Smooth learning curve

Increase performance

03

05

02

04

01

With great power comes great responsibility

Green JavaScript

Internet is consuming 21% of the electricity

check out carbon footprint

website traffic

energy intensity

data transfers

Thank you!

n.mitrovic@vegait.rs

You can find me at

Link to the slides

https://github.com/nmitrovic-vega/superpowers-web-api