BrazilJS

Share this post
Fazendo upload com controle de progresso com JavaScript
www.braziljs.org

Fazendo upload com controle de progresso com JavaScript

Felipe N. Moura
Jan 24, 2018
Comment
Share

Bom, já falamos sobre as várias formas de fazer Input de arquivos com JavaScript e também sobre como capturar fotos e gravar vídeos e áudios com getUserMedia.

Agora, vamos ver como podemos demonstrar para o usuário que estes dados estão sendo enviados para o servidor.

E vamos usar uma API nova, o XMLHttpRequest... Mas, isso não é novo!

Pois é. A especificação da última versão do XHR nos oferece algumas funcionalidades novas, entre elas, o envio de dados binários (os nossos blobs, discutidos e preparados devidamente nos posts anteriores) e, também, uma API para acompanharmos o progresso do upload.

Progressivo

Faremos isso de forma progressiva para que não tenhamos problemas com navegadores que não venham a suportar essas features.

Para acompanharmos o progresso do upload, vamos nos apoiar na propriedade upload do XHR; portanto, podemos usá-la como referência para feature detection.

Assim, podemos escolher qual será o comportamento de nossa interface enquanto acontece o upload. Dessa forma, nos certificaremos de que o navegador não irá disparar nenhum erro e que a experiência do usuário será agradável.

   if (xhr.upload) {     // exibiremos a barra de progresso   } else {     // podemos exibir alguma animação que fique se repetindo     // enquanto o upload não for finalizado   } 

Função de upload

Digamos que, ao clicar em um determinado botão, nós vamos usar o arquivo já colhido e fazer o upload. Para isso, usaremos um objeto XHR em modo POST e precisaremos dar um "append" do arquivo ao formulário que será enviado ao servidor.

Essa nossa função será uma promise, a ser resolvida assim que o upload finalizar, sendo rejeitada em caso de falha no upload.

Usaremos uma instância de FormData para enviarmos os dados ao servidor.

Neste exemplo, enviaremos os dados do form e arquivos para o path /, mas você precisará apontar este path para a rota em seu servidor que deverá tratar o form submetido.

Para este exemplo, este servidor terá acesso ao arquivo que estamos enviando por meio do nome "the-file", mas sinta-se à vontade para renomear esta variável, e claro, para enviar mais arquivos sob outros nomes. Aos olhos do servidor, este nome está para o arquivo enviado como o name está para os inputs for form.

 function uploadFile (file) {   return new Promise( (resolve, reject) => {     const xhr = new XMLHttpRequest()      let fd = new FormData()     // adicione ao fd as demais informações que você pretende enviar por POST     // ao servidor, além do(s) arquivo(s)         // agora é hora de adicionarmos o(s) arquivo(s)     fd.append('the-file', file) // nome para referência ao arquivo no formulário     xhr.open('post', '/') // path da rota no servidor      xhr.send(fd) // iniciando a requisição, enviando o FormData   } } 

Eventos

É hora de escutarmos alguns eventos para sabermos o estado de nosso XHR. Os mais tradicionais são o onload e o onerror

Antes de nosso .send, vamos acrescentar o seguinte:

     xhr.onerror = reject // em caso de erro, rejeitamos a promise     xhr.onload = event => {       // o envio ocorreu com sucesso       resolve() // resolvemos nossa promise     } 

Acompanhando o progresso

Até aqui, tudo bem. Estamos falando de um XHR tradicional. É hora de acompanharmos o progresso desse upload.

Com acesso a xhr.upload, poderemos usar um evento novo, o onprogress. Este evento será disparado, passando para nós um objeto do tipo Progress que terá as propriedades loaded e total, em que loaded é a quantidade dos bytes que já foram carregados e total é o total de bytes a serem enviados.

Como você deve ter deduzido, sim, precisaremos fazer um pequeno cálculo com essas informações se quisermos exibir a percentagem do upload.

     if (xhr.upload) {       // caso tenhamos acesso a esta informação       xhr.upload.onprogress = progress => {         console.log(Math.round((progress.loaded * 100) / progress.total) + '%')       }     } else {       // tratamento em navegadores que não suportam xhr.upload     } 

Não confunda este evento com o progress do próprio objeto XHR. Este outro evento é dedicado ao progresso do download, não do upload.

E você também pode optar por escutar o evento abort para saber quando o envio ou download foi cancelado.

Concluindo

Legal, né? Mais uma daquelas coisas que costumávamos ouvir o pessoal dizendo que precisaríamos de alguma outra tecnologia para fazer, como o Flash, ActiveX, Applets ou Java. Só pra constar, três desses quatro caras já estão mortos! #LenhaNaFogueira :p

Em resumo, nossa função de upload ficou assim:

 function uploadFile (file) {   return new Promise( (resolve, reject) => {     const xhr = new XMLHttpRequest()      let fd = new FormData()     // adicione ao fd as demais informações que você pretende enviar por POST     // ao servidor, além do(s) arquivo(s)         // agora é hora de adicionarmos o(s) arquivo(s)     fd.append('the-file', file) // nome para referência ao arquivo no formulário     xhr.open('post', '/') // path da rota no servidor      xhr.onerror = reject // em caso de erro, rejeitamos a promise     xhr.onload = event => {       // o envio ocorreu com sucesso       resolve() // resolvemos nossa promise     }      if (xhr.upload) {       // caso tenhamos acesso a esta informação       xhr.upload.onprogress = progress => {         console.log(Math.round((progress.loaded * 100) / progress.total) + '%')       }     } else {       // tratamento em navegadores que não suportam xhr.upload     }      xhr.send(fd) // iniciando a requisição, enviando o FormData   } } 

Não deixe de ler nossos outros artigos sobre as tecnologias relacionadas aqui, para se sentir mais à vontade na hora de trabalhar com essas funcionalidades.

CommentComment
ShareShare

Create your profile

0 subscriptions will be displayed on your profile (edit)

Skip for now

Only paid subscribers can comment on this post

Already a paid subscriber? Sign in

Check your email

For your security, we need to re-authenticate you.

Click the link we sent to , or click here to sign in.

TopNewCommunity

No posts

Ready for more?

© 2022 BrazilJS
Privacy ∙ Terms ∙ Collection notice
Publish on Substack Get the app
Substack is the home for great writing