Cómo verificar el estado de la conexión a Internet usando JavaScript asíncrono

¿Puede utilizar JavaScript para comprobar si su aplicación está conectada a Internet?

En este artículo, proporcionaré una respuesta actualizada a esta pregunta de detección de conexión a Internet. (¡Vaya! ¡Di eso rápido cinco veces!)

La solución utilizará la API Fetch de JavaScript y código asincrónico con Async y Await. Pero primero, veamos una solución aceptada y analicemos por qué puede no ser la mejor opción para su aplicación.

navigator.onLine

La propiedad en línea de la interfaz del navegador navigator.onLine, se utiliza con frecuencia para detectar el estado en línea y fuera de línea del navegador.

Combinado con oyentes para eventos en línea y fuera de línea, parece proporcionar una solución simple para los desarrolladores que es fácil de implementar.

Veamos cómo implementaríamos navigator.onLine

Comience agregando un detector de eventos de carga. Cuando se activa el evento de carga, el oyente verificará la propiedad en línea de la interfaz del navegador y luego mostrará el estado en línea.

La propiedad en línea del navegador proporciona una respuesta booleana (verdadera o falsa). Para finalizar la acción del oyente, usaremos una declaración ternaria para establecer el valor de visualización del estado.

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

Entonces, ¿por qué la palabra navegador? Bueno, es una referencia al navegador Netscape Navigator de los años 90.

Centre un elemento h1 en su página HTML con la identificación de "estado". Si aplica el código JavaScript anterior a su página, debería ver que se muestra "En línea".

Pero esto solo actualiza el elemento h1 cuando se carga la página. Agreguemos detectores de eventos en línea y fuera de línea para actualizar la visualización de estado en cualquier momento en que se active cualquiera de esos eventos.

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

Podemos ir a la pestaña Aplicación de Chrome Dev Tools y hacer clic en ServiceWorker para configurar el navegador para que responda como si estuviera fuera de línea.

Marque y desmarque la casilla de verificación Fuera de línea varias veces. Debería ver que la pantalla de estado responde inmediatamente a los eventos en línea y fuera de línea que se activan.

Profundicemos un poco más

A primera impresión, lo anterior parece una buena solución que es bastante simple. Desafortunadamente, a medida que leemos más sobre la propiedad en línea del navegador y los eventos en línea y fuera de línea, encontramos que hay un problema.

La búsqueda de navigator.onLine en CanIUse.com muestra un apoyo generalizado para el | estado fuera de línea que proporciona la propiedad. Sin embargo, al mirar las notas debajo de la tabla de soporte, vemos que

“Online no siempre significa conexión a Internet. También puede significar simplemente conexión a alguna red ”.

Hmm, eso arroja una llave en las obras un poco.

Por lo tanto, si realmente desea determinar el estado en línea del navegador, debe desarrollar medios adicionales para verificar.

También echemos un vistazo a la referencia de documentos de MDN para navigator.onLine. Los documentos web de MDN respaldan la información de CanIUse.com y agregan notas adicionales.

“Los navegadores implementan esta propiedad de manera diferente ... no se puede asumir que un valor verdadero significa necesariamente que el navegador puede acceder a Internet. Podría estar obteniendo falsos positivos ... "

Y eso confirma nuestros temores sobre el uso de la propiedad en línea del navegador como nuestra solución para detectar una conexión a Internet. Es una solución que puede causar estragos en nuestras aplicaciones que dependen de saber cuándo están disponibles fuentes de datos externas.

Un ejemplo es cuando intentamos determinar si una aplicación web progresiva está en línea o no. MDN incluso recomienda,

"... si realmente desea determinar el estado en línea del navegador, debe desarrollar medios adicionales para verificar".

Una búsqueda rápida en la web de "navegador en línea no funciona" revela varias publicaciones del foro en las que los que dependen de esta propiedad han tenido problemas.

Entonces, ¿cuál es la solución?

Necesitamos saber cuándo nuestra aplicación está realmente conectada a Internet y no solo a un enrutador o red local. Volvamos a nuestro archivo JavaScript y comencemos de nuevo.

La idea es hacer una solicitud y manejarla con elegancia con detección de errores si falla. Si la solicitud tiene éxito, estamos en línea, y si falla, no.

Vamos a solicitar una pequeña imagen a intervalos para determinar el estado en línea. JavaScript moderno proporciona la API Fetch y código asincrónico con Async y Await. Usaremos estas herramientas para lograr nuestro objetivo.

checkOnlineStatus ()

Comencemos creando una función de flecha asíncrona llamada checkOnlineStatus. La función devolverá verdadero o falso como lo hace la propiedad en línea del navegador.

Dentro de la función, configuraremos un bloque de prueba donde esperamos una solicitud de búsqueda para una imagen de un píxel. Asegúrese de que su trabajador de servicio no esté almacenando en caché esta imagen.

Los códigos de respuesta HTTP entre 200 y 299 indican éxito y devolveremos el resultado de la comparación del código de estado. Esto será cierto si el estado de respuesta es de 200 a 299 y falso en caso contrario.

También tenemos que proporcionar un bloque de captura que detecta el error si falla la solicitud. Devolveremos falso en el bloque de captura para indicar que definitivamente estamos desconectados si esto sucede.

const checkOnlineStatus = async () => { try { const online = await fetch("/1pixel.png"); return online.status >= 200 && online.status < 300; // either true or false } catch (err) { return false; // definitely offline } };

A continuación, usaremos el método setInterval y le pasaremos una función asíncrona anónima. La función async esperará el resultado de nuestra función checkOnlineStatus. Luego usaremos una declaración ternaria con el resultado para mostrar el estado actual en línea.

Para probar este ejemplo, establezca el intervalo de retraso en cada 3 segundos (3000 milisegundos). Sin embargo, esto es demasiado frecuente. Verificar cada 30 segundos (30000 milisegundos) puede ser suficiente para sus necesidades reales.

setInterval(async () => { const result = await checkOnlineStatus(); const statusDisplay = document.getElementById("status"); statusDisplay.textContent = result ? "Online" : "OFFline"; }, 3000); // probably too often, try 30000 for every 30 seconds

Con nuestro nuevo código guardado, volvamos a visitar la pestaña Aplicación en Chrome Dev Tools para probar la respuesta sin conexión.

I almost forgot to include the load event listener with async functionality! The load event detection is probably only important if you have a Progressive Web App utilizing a service worker for offline availability. Otherwise, your web page or app simply won't load without a connection.

Here's the new load event listener:

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

A Final Thought

The above interval code is good for displaying a connection status in your app. That said, I don't suggest relying on a connection status that was checked 20 or 30 seconds prior to making a critical data request in your application.

Therefore, you should call the checkOnlineStatus function directly prior to the request and evaluate the response before requesting data.

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

Conclusion

While navigator.onLine is widely supported, it provides unreliable results when determining if our applications are truly connected to the Internet. Utilizing the Fetch API and asynchronous JavaScript, we can quickly code a more reliable solution.

Here’s a link to the code gist on GitHub, and here's a video tutorial I put together: