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:


  • methodGET, POST, PUT, DELETE, HEAD
  • url – URL da solicitação
  • headers – associado Headers objeto
  • referrer – referenciador da solicitação
  • modecors, no-cors, same-origin
  • credentials – os cookies devem acompanhar a solicitação? omit, same-origin
  • redirectfollow, error, manual
  • integrity – valor de integridade do sub-recurso
  • cache – 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:


  • typebasic, cors
  • url
  • useFinalURL – Booleano para if url é o URL final
  • status – 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.