Eu quero usar promessas (nativas) no meu aplicativo front-end para executar solicitações XHR, mas sem toda a bobagem de uma estrutura massiva.
Eu quero o meu xhr para retornar uma promessa, mas isso não funciona (dando-me: Uncaught TypeError: Promise resolver undefined is not a function
)
function makeXHRRequest (method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function() { return new Promise().resolve(); };
xhr.onerror = function() { return new Promise().reject(); };
xhr.send();
}
makeXHRRequest('GET', 'http://example.com')
.then(function (datums) {
console.log(datums);
});
javascript
xmlhttprequest
promise
SomeKittens
fonte
fonte
Respostas:
Suponho que você saiba como fazer uma solicitação XHR nativa (você pode atualizar aqui e aqui )
Como qualquer navegador que suporte promessas nativas também suportará
xhr.onload
, podemos pular todas asonReadyStateChange
ferramentas do tom. Vamos dar um passo atrás e começar com uma função básica de solicitação XHR usando retornos de chamada:Viva! Isso não envolve nada terrivelmente complicado (como cabeçalhos personalizados ou dados POST), mas é suficiente para nos levar adiante.
O construtor de promessas
Podemos construir uma promessa como esta:
O construtor da promessa assume uma função que recebe dois argumentos (vamos chamá-los
resolve
ereject
). Você pode pensar neles como retornos de chamada, um para o sucesso e outro para o fracasso. Os exemplos são impressionantes, vamos atualizarmakeRequest
com este construtor:Agora podemos explorar o poder das promessas, encadeando várias chamadas XHR (e
.catch
isso desencadeará um erro em qualquer uma das chamadas):Podemos melhorar ainda mais isso, adicionando parâmetros POST / PUT e cabeçalhos personalizados. Vamos usar um objeto de opções em vez de vários argumentos, com a assinatura:
makeRequest
agora se parece com isso:Uma abordagem mais abrangente pode ser encontrada na MDN .
Como alternativa, você pode usar a API de busca ( polyfill ).
fonte
responseType
, autenticação, credenciaistimeout
... Eparams
objetos devem apoiar blobs / bufferviews eFormData
instânciasxhr.status
exhr.statusText
com erro, pois eles estão vazios nesse caso.resolve(xhr.response | xhr.responseText);
Na maioria dos navegadores, a repsonse está em responseText enquanto isso.Isso pode ser tão simples quanto o código a seguir.
Lembre-se de que esse código acionará apenas o
reject
retorno de chamada quandoonerror
for chamado ( apenas erros de rede ) e não quando o código de status HTTP significar um erro. Isso também excluirá todas as outras exceções. Lidar com isso deve depender de você, IMO.Além disso, é recomendável chamar o
reject
retorno de chamada com uma instânciaError
e não o evento em si, mas por uma questão de simplicidade, deixei como está.E invocando poderia ser o seguinte:
fonte
xhr.send(requestBody)
Para quem pesquisa isso agora, você pode usar a função de busca . Tem algum suporte muito bom .
Em primeiro lugar, usei a resposta de @ SomeKittens, mas depois descobri
fetch
que isso é feito para mim fora da caixa :)fonte
fetch
função, mas o GitHub publicou um polyfill .fetch
, pois ainda não suporta cancelamento.Penso que podemos tornar a resposta principal muito mais flexível e reutilizável se não criarmos o
XMLHttpRequest
objeto. O único benefício de fazer isso é que não precisamos escrever 2 ou 3 linhas de código para fazê-lo, e isso tem a enorme desvantagem de tirar nosso acesso a muitos dos recursos da API, como definir cabeçalhos. Ele também oculta as propriedades do objeto original do código que deve lidar com a resposta (para sucessos e erros). Para que possamos criar uma função mais flexível e amplamente aplicável, basta aceitar oXMLHttpRequest
objeto como entrada e transmiti-lo como resultado .Essa função converte um
XMLHttpRequest
objeto arbitrário em uma promessa, tratando códigos de status diferentes de 200 como um erro por padrão:Essa função se encaixa muito naturalmente em uma cadeia de
Promise
s, sem sacrificar a flexibilidade daXMLHttpRequest
API:catch
foi omitido acima para manter o código de exemplo mais simples. Você deve sempre ter um, e é claro que podemos:E desabilitar a manipulação do código de status HTTP não exige muita alteração no código:
Nosso código de chamada é mais longo, mas conceitualmente, ainda é simples entender o que está acontecendo. E não precisamos reconstruir toda a API de solicitação da Web apenas para suportar seus recursos.
Também podemos adicionar algumas funções de conveniência para organizar nosso código:
Então nosso código se torna:
fonte
A resposta de jpmc26 é quase perfeita na minha opinião. Existem algumas desvantagens:
POST
que solicitações configurem o corpo da solicitação.send
chamada está oculta dentro de uma função.O macaco que corrige o objeto xhr trata desses problemas:
Agora, o uso é tão simples quanto:
Obviamente, isso apresenta uma desvantagem diferente: o patch do macaco prejudica o desempenho. No entanto, isso não deve ser um problema, supondo que o usuário esteja aguardando principalmente pelo resultado do xhr, que a própria solicitação leve ordens de magnitude mais longas que a configuração da chamada e que as solicitações do xhr não sejam enviadas com frequência.
PS: E, claro, se estiver direcionando navegadores modernos, use buscar!
PPS: Foi observado nos comentários que esse método altera a API padrão, o que pode ser confuso. Para maior clareza, pode-se aplicar um método diferente ao objeto xhr
sendAndGetPromise()
.fonte
send
chamada real, mas também pode confundir os leitores que sabem quesend
não têm valor de retorno. O uso de chamadas mais explícitas torna mais claro que lógica adicional foi invocada. Minha resposta precisa ser ajustada para lidar com argumentossend
; no entanto, provavelmente é melhor usarfetch
agora.