Artigos

Real-Time com XMLHttpRequest

cookiemonster_xmlhttprequest

O XMLHttpRequest ou XHR, mudou tudo. Graças a essa API, o client-side pode transferir dados via Javascript. Ele inseriu o “D” na frente do HTML e nos permitiu obter assincronismo em nossas aplicações web. Antes dele, uma página precisava ser recarregada para enviar ou receber dados do servidor. Apesar de estar presente nos browsers desde o Internet Explorer 5, o XHR ainda é essencial para desenvolvermos aplicações web ricas e pode também ser usado – apesar de existir, hoje, tecnologias como websocket – para aplicações de tempo real.

XHR nos fornece uma maneira eficiente de sincronizar atualizações entre cliente e servidor. Quando necessário, uma requisição XHR envia dados para o servidor. O problema é o inverso.

Notificações em tempo real

O HTTP não fornece nenhuma maneira de o servidor iniciar uma nova conexão com o cliente. Para receber notificações, o cliente deve fazer polling, ou seja, fazer requisições periódicas ao servidor para pegar atualizações. Uma outra forma seria utilizar streaming, mas o suporte a streaming do XHR é limitado.

Dependendo da aplicação, podemos conviver com um delay de segundos, por exemplo. Mas algumas aplicações podem ter um overhead na casa dos milisegundos. A melhor forma de transportar dados irá depender.

Polling é muito simples de implementar. Piece of cake. Mas é frequentemente ineficiente. O intervalo de tempo de cada requisição é crítico. Imagine seu navegador fazendo requisições periódicas em frações de segundo para o servidor. Agora imagine milhões de navegadores fazendo a mesma coisa. Um cenário de terror pra qualquer sysadmin. Vamos olhar a função abaixo:

[code language=”javascript”]

function checkUpdates(url){
var xhr = new XMLHttpRequest();
xhr.open(‘GET’, url);
xhr.onload = function(){ /* processa atualizações vindas do servidor */ };
xhr.send();
}

setInterval(checkUpdates(‘/updates’), 2000);

[/code]

Nesse exemplo, ocorre a checagem por atualizações a cada 2 segundos.

Cada requisição é comumente chamada de ajax. Ele nada mais é que uma requisição HTTP padrão. Muitas dessas requisições serão desnecessárias, pois não virão atualizações na resposta. Dependendo do caso, essas requisições desnecessárias podem ter um custo alto. Podem sobrecarregar a rede e o servidor, além de acabar com a bateria de dispositivos móveis. Uma requisição HTTP 1.x tem aproximadamente 800 bytes sem cookies. Imagine milhares de clientes trafegando 800 bytes a cada 2 segundos. E agora? Websocket? Ainda não. E se existisse uma maneira de eliminar essas requisições desnecessárias? Pior que existe ó.

Long-Polling

Long-polling, a.k.a COMET, a.k.a HTTP push, a.k.a Ajax reverso. Esta técnica nos permite manter a mesma conexão até que a atualização esteja disponível.

HTTP poll vs Long-polling
HTTP poll vs Long-polling

A conexão fica aberta até a atualização estar disponível. Uma vez que a resposta é entregue ao cliente, a conexão é fechada e outra requisição long-polling é enviada ao servidor, aguardando a próxima mensagem.

[code language=”javascript”]

function checkUpdates(url){
var xhr = new XMLHttpRequest();
xhr.open(‘GET’, url);
xhr.onload = function(){

checkUpdates(‘/updates’);
};

xhr.send();
}

checkUpdates(‘/updates’);

[/code]

Pode testar. A bagaça realmente funciona. Mas e aí? Long-polling é sempre eficiente? Não. Só será eficiente quando o intervalo de tempo de atualizações no servidor for mais ou menos constante. Caso contrário, pode gerar mais requisições ao servidor do que o polling com setInterval.

Em alguns casos, long-polling resolve. A primeira versão do chat do facebook utilizava essa técnica. No entanto, hoje existem formas mais eficientes como websocket e server-sent events. Mais eficientes e bem mais trabalhosos.

Até a próxima.

3 Comentários

  • Kaio Valente

    Bacana Paulo, interessante essa abordagem. Outra questão relacionada acerca do mesmo problema, mas falando em back-end, seria tratar os códigos de status HTTP corretamente, geralmente usa-se 200 pra tudo, em caso de sucesso. Mas em endopoints REST pode-se usar também 201, 202, 204 e 304 (not modified), cada um com sua finalidade específica, a verificação do status code poderia ajudar a ganhar alguns milisegundos no retorno do request.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *