Articolo originale: How to Check Internet Connection Status Using Async JavaScript

È possibile utilizzare JavaScript per controllare se la tua app è connessa ad internet?

In questo articolo, ti fornirò una risposta aggiornata a questa domanda.

La soluzione farà uso dell'API Fetch di Javascript e della programmazione asincrona con il costrutto Async & Await. Prima però, diamo un'occhiata ad un approccio comunemente accettato e vediamo perché potrebbe non essere la scelta migliore da implementare nella tua applicazione.

La proprietà "online" dell'interfaccia navigator, navigator.onLine, è utilizzata frequentemente per rilevare lo stato online/offline del browser.

Combinata con i listener per gli eventi online ed offline, sembra fornire agli sviluppatori una soluzione semplice e facile da implementare.

Diamo un'occhiata a come implementare navigator.onLine

Iniziamo aggiungendo un event listener all'evento "load". Quando l'evento "load" viene attivato, il listener controlla la proprietà "online" dell'interfaccia "navigator" e quindi mostra lo stato della connessione.

La proprietà "online" di navigator fornisce una risposta booleana (vero o falso). Per terminare l'azione del listener, utilizzeremo un operatore ternario per impostare il valore dell'elemento DOM che mostra lo stato della connessione.

window.addEventListener("load", (event) => {
  const statusDisplay = document.getElementById("status");
  statusDisplay.textContent = navigator.onLine ? "Online" : "OFFline";
});

Ma perché la parola "navigator" (navigatore)? È un riferimento al browser Netscape Navigator in uso negli anni '90.

Posiziona un elemento h1 al centro nella tua pagina HTML con l'id "status".  Se applichi il codice JavaScript riportato qui sopra alla tua pagina, dovresti vedere comparire il testo "Online".

Tuttavia questo aggiorna solamente l'elemento h1 quando la pagina viene caricata. Proviamo ad aggiungere dei listener per gli eventi offline e online che aggiornano il display dello stato ogni volta che l'uno o l'altro evento viene attivato.

window.addEventListener("offline", (event) => {
  const statusDisplay = document.getElementById("status");
  statusDisplay.textContent = "OFFline";
});

window.addEventListener("online", (event) => {
  const statusDisplay = document.getElementById("status");
  statusDisplay.textContent = "Online";
});

Puoi andare alla scheda Applicazione degli strumenti Chrome per sviluppatori (Chrome Dev Tools > Application Tab )  e cliccare su ServiceWorker per impostare il browser in modo che risponda come se fosse offline.

Seleziona e deseleziona la checkbox Offline alcune volte. Dovresti vedere il display di stato rispondere immediatamente agli eventi offline e online che sono stati attivati.

offline_check_nav_online
strumenti Chrome per sviluppatori > Applicazione> Service Workers > Checkbox Offline

Andiamo un po' più a fondo

A prima vista, quanto riportato sopra sembra una buona soluzione, oltre che abbastanza semplice. Sfortunatamente, se leggiamo qualcosa in più nella documentazione della proprietà "online" di navigator e sugli eventi online/offline, troviamo che c'è un problema.

Una ricerca di navigator.online su CanIUse.com mostra il supporto diffuso fornito dai browser alla proprietà per lo stato online | offline. Tuttavia, guardano alle note riportate sotto la tabella relativa al supporto nelle diverse versioni, possiamo leggere:

“Online non significa sempre connessione ad Internet. Può anche significare connessione a qualche rete”.

Mmh, questo ci mette un po' i bastoni tra le ruote.

Così, se volessi veramente determinare lo stato online del browser, dovresti sviluppare metodi addizionali per la questa verifica.

Diamo anche un'occhiata al riferimento sulla documentazione MDN per navigator.onLine.

I browsers implementano questa proprietà in modo differente...non si può assumere che un valore true significhi necessariamente che il browser abbia accesso ad internet. Si potrebbe incorrere in falsi positivi...

Questo conferma i nostri timori nell'utilizzare la proprietà online di navigator come soluzione per verificare la connessione Internet. È una soluzione che può devastare la nostra applicazione se questa dipende dalla conoscenza di quando delle sorgenti esterne di dati sono disponibili.

Uno di tali esempi è quando proviamo a determinare se una Web App Progressiva (Progressive Web App o PWA) sia online oppure no. MDN raccomanda persino,

“...se realmente si vuole determinare lo stato della connessione del browser, si dovrebbero sviluppare metodi addizionali di verifica.

Una ricerca rapida nel web per "navigator online non funziona" (“navigator online not working”) fornisce diversi post nei forum di chi ha riscontrato problemi dipendendo da questa proprietà.

Allora, qual è la soluzione?

Ci serve sapere quando la nostra applicazione è realmente connessa a Internet e non solamente ad un router o una rete locale. Torniamo al nostro file JavaScript e ricominciamo da capo.

L'idea è fare una richiesta HTTP e trattarla elegantemente gestendo gli errori se questa fallisce. Se la richiesta ha successo, siamo online, mentre se fallisce, non lo siamo.

Richiederemo una piccola immagine a un intervallo temporale predefinito per determinare lo stato online. Il moderno linguaggio JavaScript fornisce l'API Fetch e la programmazione asincrona con il costrutto Async & Await. Utilizzeremo questi strumenti per portare a termine il nostro obiettivo.

La funzione checkOnlineStatus()

Iniziamo creando una funzione freccia asincrona denominata checkOnlineStatus. La funziona restituirà vero o falso come la proprietà online di navigator.

All'interno della funzione, impostiamo un blocco try dove attendiamo una richiesta fetch per una immagine da 1 pixel. Assicurati che il tuo service worker non stia salvando questa immagine nella cache.

Un codice di risposta HTTP tra 200 e 299 indica che la richiesta ha avuto successo, pertanto forniremo il risultato del confronto sul codice di stato. Questo sarà vero se lo stato della risposta è compreso tra 200 e 299 e falso per gli altri valori.

Inoltre dobbiamo fornire un blocco catch che intercetti l'errore se la richiesta fallisce. La funzione ritornerà falso all'interno del blocco catch per indicare che siamo veramente offline, qualora accadesse.

const checkOnlineStatus = async () => {
  try {
    const online = await fetch("/1pixel.png");
    return online.status >= 200 && online.status < 300; // può essere vera o falsa
  } catch (err) {
    return false; // sicuramente offline
  }
};

Come prossimo passo, utilizzeremo il metodo setInterval e lo passeremo ad una funziona async anonima. La funzione async attenderà il risultato della nostra funzione checkOnlineStatus. Utilizzeremo quindi un operatore ternario con tale risultato per mostrare lo stato corrente della connessione.

Per testare questo esempio, imposta l'intervallo temporale ad ogni 3 secondi (3'000 millisecondi). Ma così è troppo frequente. Controllare ogni 30 secondi (30'000 millisecondi) potrebbe essere sufficiente per le tue effettive necessità.

setInterval(async () => {
  const result = await checkOnlineStatus();
  const statusDisplay = document.getElementById("status");
  statusDisplay.textContent = result ? "Online" : "OFFline";
}, 3000); // probabilmente troppo frequente, usa 30'000  per controllare ogni 30 secondi

Con il nostro nuovo codice salvato, torniamo alla scheda Application negli strumenti per sviluppatori di Chrome per testare la risposta quando siamo offline.

offline_check_fetch
strumenti Chrome per sviluppatori > Applicazione> Service Workers > Checkbox Offline

Ho quasi dimenticato di includere il listener dell'evento "load" con funzionalità asincrona! Il rilevamento dell'evento "load" è importante forse nell'unico caso in cui si abbia una Web App Progressiva che utilizzi un service worker per essere disponibile in modalità offline. In caso contrario, la tua pagina web o la tua web app semplicemente non viene caricata senza una connessione.

Ecco qui il nuovo listener dell'evento load:

window.addEventListener("load", async (event) => {
  const statusDisplay = document.getElementById("status");
  statusDisplay.textContent = (await checkOnlineStatus())
    ? "Online"
    : "OFFline";
});

Una considerazione finale

Il codice riportato sopra con le richieste HTTP effettuate ad intervalli prestabiliti va bene per mostrare lo stato della connessione della tua App. Detto questo, non suggerisco di affidarsi ad uno stato di connessione che viene controllato 20 o 30 secondi prima di effettuare una richiesta di dati critica nella tua applicazione.

In questo caso, dovresti invocare la funzione checkOnlineStatus direttamente prima della richiesta e valutare la risposta prima di richiedere i dati.

const yourDataRequestFunction = async () => {
    const online = await checkOnlineStatus();
    if (online) {
    	// make data request
    }
}

Conclusioni

Anche se navigator.onLine è ampiamente supportato nei diversi browser, fornisce risultati inaffidabili quando è necessario determinare se la nostra applicazione è realmente connessa a Internet. Utilizzando l'API Fetch e la programmazione asincrona in Javascript, possiamo rapidamente programmare una soluzione più affidabile.

Qui c'è un link al code gist su GitHub, e qui c'è un video tutorial che ho realizzato (video in lingua originale):