Um dos segredos mais mal guardados sobre AJAX na Web é que a API subjacente a ele, XMLHttpRequest
, não foi realmente criada para o uso que estamos fazendo dela. Fizemos bem em criar APIs elegantes em torno do XHR, mas sabemos que podemos fazer melhor. Nosso esforço para fazer melhor é o fetch
API. Vamos dar uma olhada básica na nova window.fetch
disponível agora no Firefox e no Chrome Canary.
XMLHttpRequest
XHR é um pouco complicado demais, na minha opinião, e não me pergunte por que “XML” é maiúsculo e “Http” é maiúsculo. De qualquer forma, é assim que o senhor usa o XHR agora:
// Just getting XHR is a mess! if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // Open, send. request.open('GET', 'https://davidwalsh.name/ajax-endpoint', true); request.send(null);
É claro que nossas estruturas JavaScript tornam o XHR mais agradável de se trabalhar, mas o que o senhor vê acima é um simples exemplo da bagunça do XHR.
Básico fetch
Utilização
A fetch
agora é fornecida na função global window
com o primeiro argumento sendo o URL:
// url (required), options (optional) fetch('https://davidwalsh.name/some/url', { method: 'get' }).then(function(response) { }).catch(function(err) { // Error :( });
Assim como a versão atualizada do API da bateria, a API de busca usa Promessas em JavaScript para lidar com resultados/callbacks:
// Simple response handling fetch('https://davidwalsh.name/some/url').then(function(response) { }).catch(function(err) { // Error :( }); // Chaining for more "advanced" handling fetch('https://davidwalsh.name/some/url').then(function(response) { return //... }).then(function(returnedValue) { // ... }).catch(function(err) { // Error :( });
Se o senhor não está acostumado a then
ainda não está acostumado, acostume-se, pois logo ele estará em todos os lugares.
Cabeçalhos de solicitação
A capacidade de definir cabeçalhos de solicitação é importante para a flexibilidade da solicitação. O senhor pode trabalhar com cabeçalhos de solicitação executando new Headers()
:
// Create an empty Headers instance var headers = new Headers(); // Add a few headers headers.append('Content-Type', 'text/plain'); headers.append('X-My-Custom-Header', 'CustomValue'); // Check, get, and set header values headers.has('Content-Type'); // true headers.get('Content-Type'); // "text/plain" headers.set('Content-Type', 'application/json'); // Delete a header headers.delete('X-My-Custom-Header'); // Add initial values var headers = new Headers({ 'Content-Type': 'text/plain', 'X-My-Custom-Header': 'CustomValue' });
O senhor pode usar o append
, has
, get
, set
, e delete
para modificar os cabeçalhos de solicitação. Para usar os cabeçalhos de solicitação, crie um Request
:
var request = new Request('https://davidwalsh.name/some-url', { headers: new Headers({ 'Content-Type': 'text/plain' }) }); fetch(request).then(function() { /* handle response */ });
Vamos dar uma olhada no que o Response
e Request
do!
Solicitação
A Request
representa a parte da solicitação de um fetch
chamada. Ao passar a fetch
a Request
o senhor pode fazer solicitações avançadas e personalizadas:
method
–GET
,POST
,PUT
,DELETE
,HEAD
url
– URL da solicitaçãoheaders
– associadoHeaders
objetoreferrer
– referenciador da solicitaçãomode
–cors
,no-cors
,same-origin
credentials
– os cookies devem acompanhar a solicitação?omit
,same-origin
redirect
–follow
,error
,manual
integrity
– valor de integridade do sub-recursocache
– modo cache (default
,reload
,no-cache
)
Uma amostra Request
pode ser semelhante:
var request = new Request('https://davidwalsh.name/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }); // Now use it! fetch(request).then(function() { /* handle response */ });
Somente o primeiro parâmetro, o URL, é necessário. Cada propriedade torna-se somente leitura quando o parâmetro Request
tiver sido criada. Também é importante observar que o Request
tem um clone
que é importante ao usar o método fetch
na API do Service Worker: uma solicitação é um fluxo e, portanto, deve ser clonada ao ser passada para outro fetch
chamada.
O fetch
no entanto, funciona como a assinatura do Request
portanto, o senhor também poderia fazer isso:
fetch('https://davidwalsh.name/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }).then(function() { /* handle response */ });
O senhor provavelmente só usará Request
dentro de Service Workers, já que o Request
e fetch
as assinaturas podem ser as mesmas. Em breve, a publicação sobre o ServiceWorker!
Resposta
O fetch
‘s then
é fornecido um método Response
mas o senhor também pode criar manualmente a instância Response
manualmente – outra situação que o senhor pode encontrar ao usar service workers. Com um Response
o senhor pode configurar:
type
–basic
,cors
url
useFinalURL
– Booleano para ifurl
é o URL finalstatus
– código de status (ex:200
,404
, etc.)ok
– Booleano para resposta bem-sucedida (status no intervalo 200-299)statusText
– código de status (ex:OK
)headers
– Objeto de cabeçalhos associado à resposta.
// Create your own response for service worker testing // new Response(BODY, OPTIONS) var response = new Response('.....', { ok: false, status: 404, url: '/' }); // The fetch's `then` gets a Response instance back fetch('https://davidwalsh.name/') .then(function(responseObj) { console.log('status: ', responseObj.status); });
O Response
também fornece os seguintes métodos:
clone()
– Cria um clone de um objeto Response.error()
– Retorna um novo objeto Response associado a um erro de rede.redirect()
– Cria uma nova resposta com um URL diferente.arrayBuffer()
– Retorna uma promessa que é resolvida com um ArrayBuffer.blob()
– Retorna uma promessa que é resolvida com um Blob.formData()
– Retorna uma promessa que é resolvida com um objeto FormData.json()
– Retorna uma promessa que é resolvida com um objeto JSON.text()
– Retorna uma promessa que é resolvida com um USVString (texto).
Manipulação de JSON
Digamos que o senhor faça uma solicitação de JSON – os dados de retorno de chamada resultantes têm um json
para converter os dados brutos em um objeto JavaScript:
fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { // Convert to JSON return response.json(); }).then(function(j) { // Yay, `j` is a JavaScript object console.log(j); });
É claro que isso é uma simples JSON.parse(jsonString)
, mas o json
é um atalho útil.
Manipulação de respostas básicas de texto/HTML
JSON nem sempre é o formato de resposta de solicitação desejado, portanto, veja como o senhor pode trabalhar com uma resposta em HTML ou texto:
fetch('/next/page') .then(function(response) { return response.text(); }).then(function(text) { // <!DOCTYPE .... console.log(text); });
O senhor pode obter o texto da resposta por meio do encadeamento de Promise’s then
da Promise junto com o método text()
method.
Manipulação de respostas de blob
Se o senhor quiser carregar uma imagem via fetch, por exemplo, isso será um pouco diferente:
fetch('https://davidwalsh.name/flowers.jpg') .then(function(response) { return response.blob(); }) .then(function(imageBlob) { document.querySelector('img').src = URL.createObjectURL(imageBlob); });
O blob()
do mixin Body recebe um fluxo Response e o lê até o fim.
Posting Form Data
Outro caso de uso comum para AJAX é o envio de dados de formulário – veja como o senhor usaria fetch
para postar dados de formulário:
fetch('https://davidwalsh.name/submit', { method: 'post', body: new FormData(document.getElementById('comment-form')) });
E se o senhor quiser fazer um POST JSON para o servidor:
fetch('https://davidwalsh.name/submit-json', { method: 'post', body: JSON.stringify({ email: document.getElementById('email').value, answer: document.getElementById('answer').value }) });
Muito fácil e muito agradável aos olhos também!
História não escrita
Enquanto fetch
seja uma API mais agradável de usar, a API atual não permite o cancelamento de uma solicitação, o que a torna inviável para muitos desenvolvedores;
O novo fetch
parece muito mais limpa e simples de usar do que a XHR. Afinal de contas, ela foi criada para que pudéssemos fazer AJAX da maneira correta; fetch
tem a vantagem da retrospectiva. Mal posso esperar até que o fetch
tenha um suporte mais amplo!
O objetivo é ser uma introdução ao fetch
. Para uma análise mais aprofundada, visite Introdução ao Fetch. E se o senhor estiver procurando um polyfill, confira a implementação do GitHub.