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,HEADurl– URL da solicitaçãoheaders– associadoHeadersobjetoreferrer– referenciador da solicitaçãomode–cors,no-cors,same-origincredentials– os cookies devem acompanhar a solicitação?omit,same-originredirect–follow,error,manualintegrity– 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,corsurluseFinalURL– 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.