Artigo original: https://www.freecodecamp.org/news/how-to-check-internet-connection-status-with-javascript/

Você pode usar JavaScript para verificar se sua aplicação está conectada à internet?

Neste artigo, fornecerei uma resposta atualizada para esta pergunta de detecção de conexão com a Internet.

A solução usará a API Fetch do JavaScript e código assíncrono com Async e Await. Primeiro, no entanto, vamos olhar para uma solução aceita e discutir por que ela pode não ser a melhor escolha para a sua aplicação.

A propriedade on-line da interface do navegador, navigator.onLine, é frequentemente usada para detectar o status on-line e off-line do navegador.

Combinado com ouvintes para os eventos online e offline, ele parece fornecer uma solução simples para desenvolvedores que é fácil de implementar.

Vejamos como implementaríamos navigator.onLine

Comece adicionando um ouvinte de eventos de carregamento. Quando o evento load for acionado, o ouvinte verificará a propriedade online da interface do navegador e, em seguida, exibirá o status "online".

A propriedade on-line do navegador fornece uma resposta booleana (true ou false). Para concluir a ação do ouvinte, usaremos uma instrução ternária para definir o valor de exibição de status.

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

Então, por que a palavra navigator? Bem, é uma referência ao navegador Netscape Navigator dos anos 90.

Centralize um elemento h1 em sua página HTML com o id de "status". Se você aplicar o código JavaScript acima à sua página, você deverá vê-lo exibir "Online".

Isso, porém, só atualiza o elemento h1 quando a página é carregada. Vamos adicionar ouvintes de eventos off-line e on-line para atualizar a exibição de status sempre que um desses eventos for acionado.

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 na guia Application das ferramentas do desenvolvedor do Chrome e clicar em Service Workers para configurar o navegador para responder como se estivesse off-line.

Marque e desmarque a caixa de seleção Offline algumas vezes. Você deve ver a exibição de status responder imediatamente aos eventos offline e online que são disparados.

offline_check_nav_online
Ferramentas do desenvolvedor do Chrome > Guia Application > Service Workers > caixa de seleção Offline

Seguindo adiante

À primeira impressão, o que vemos acima parece ser uma boa solução e bastante simples. Infelizmente, à medida que lemos mais sobre a propriedade online do navegador e sobre os eventos online e offline, descobrimos que há um problema.

Ao procurar por navigator.onLine no CanIUse.com, vemos que ele tem um suporte amplo para o status online | offline fornecido pela propriedade. Porém, ao olhar as notas abaixo da tabela de suporte, vemos que

"Online nem sempre significa conexão com a Internet. Também pode querer dizer apenas que há conexão com alguma rede."

Bem, isso pode atrapalhar um pouco nossos planos.

Então, se você realmente quer determinar o status on-line do navegador, você deve desenvolver meios adicionais para verificação.

Vamos dar uma olhada na referência da documentação da MDN para navigator.onLine (em inglês). A documentação da web da MDN confirma o que diz a informação do CanIUse.com, adicionando algo importante.

"Os navegadores implementam essa propriedade de maneiras diferentes... não se deve assumir que um valor true seja necessariamente acesso do navegador à internet. Você pode estar recebendo um falso positivo..."

Isso confirma nossos temores sobre o uso da propriedade online do navegador como nossa solução para detectar uma conexão com a Internet. É uma solução que pode causar estragos em nossas aplicações que dependem de saber quando fontes de dados externas estão disponíveis.

Um exemplo é quando estamos tentando determinar se uma Progressive Web App está on-line ou não.

"...se quiser realmente determinar o status on-line do navegador, é preciso desenvolver meios adicionais de verificação."

Uma busca rápida na web para "navigator online not working" (navigator online não funciona, em português) revela diversas publicações em fóruns onde aqueles que dependiam dessa propriedade tiveram problemas.

Qual a solução, então?

Precisamos saber quando nossa aplicação está realmente conectada à Internet e não apenas a um roteador ou rede local. Vamos voltar ao nosso arquivo JavaScript e começar de novo.

A ideia é fazer uma solicitação e tratá-la gentilmente com a captura de erros se ela falhar. Se a solicitação for bem-sucedida, estaremos on-line e, se falhar, não estaremos.

Vamos solicitar uma pequena imagem em um intervalo para determinar o status on-line. O JavaScript moderno fornece a API Fetch e código assíncrono, com Async e Await. Usaremos essas ferramentas para atingir nosso objetivo.

checkOnlineStatus()

Vamos começar criando uma arrow function assíncrona, chamada checkOnlineStatus. A função retornará true ou false, como faz a propriedade online do navegador.

Dentro da função, vamos configurar um bloco try, onde aguardamos uma solicitação de busca para uma imagem de um pixel. Verifique se o service worker não está armazenando essa imagem em cache.

Códigos de resposta HTTP entre 200 e 299 indicam êxito. Retornaremos o resultado da comparação do código de status. Ele será true, se o status da resposta for de 200 a 299, ou false, caso contrário.

Também temos que fornecer um bloco catch, que detecta o erro se a solicitação falhar. Retornaremos false no bloco catch para indicar que estamos definitivamente off-line se isso acontecer.

const checkOnlineStatus = async () => {
  try {
    const online = await fetch("/1pixel.png");
    return online.status >= 200 && online.status < 300; // true ou false
  } catch (err) {
    return false; // definitivamente off-line
  }
};

Em seguida, usaremos o método setInterval e passaremos a ele uma função assíncrona anônima. A função assíncrona aguardará o resultado da nossa função checkOnlineStatus. Em seguida, usaremos uma instrução ternária com o resultado para exibir o status on-line atual.

Para testar esse exemplo, defina o atraso do intervalo para cada 3 segundos (3000 milissegundos). Isso, porém, é muito frequente. Verificar a cada 30 segundos (30000 milissegundos) pode ser o suficiente para suas necessidades reais.

setInterval(async () => {
  const result = await checkOnlineStatus();
  const statusDisplay = document.getElementById("status");
  statusDisplay.textContent = result ? "Online" : "OFFline";
}, 3000); // é provável que isso seja muito frequente. Experimente 30000 para cada 30 segundos

Salvando nosso novo código, vamos rever a guia Application nas ferramentas do desenvolvedor do Chrome e testar a resposta off-line.

offline_check_fetch
Ferramentas do desenvolvedor do Chrome > Guia Application > Service Workers > caixa de seleção Offline

Quase esqueci de incluir o ouvinte de eventos de carregamento com funcionalidade assíncrona! A detecção de eventos de carregamento, provavelmente, só será importante se você tiver uma Progressive Web App utilizando um service worker para disponibilidade off-line. Caso contrário, sua página da web ou aplicação simplesmente não será carregada sem uma conexão.

Aqui está o novo ouvinte de evento de carregamento (load):

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

Parte final

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
    }
}

Conclusão

O código de intervalo acima é bom para exibir um status de conexão em sua aplicação. Dito isso, não sugiro confiar em um status de conexão que foi verificado 20 ou 30 segundos antes de fazer uma solicitação de dados críticos em sua aplicação.

Aqui você tem um link para o gist do código no GitHub. Abaixo, você tem um link para o tutorial em vídeo que eu fiz: