Je veux utiliser des promesses (natives) dans mon application frontend pour effectuer une requête XHR mais sans toute la folie d'un framework massif.
Je veux que mon XHR pour revenir une promesse , mais cela ne fonctionne pas (me donner: 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
Certains chatons
la source
la source
Réponses:
Je suppose que vous savez comment faire une requête XHR native (vous pouvez brosser ici et ici )
Étant donné que tout navigateur qui prend en charge les promesses natives le prendra également en charge
xhr.onload
, nous pouvons ignorer toute laonReadyStateChange
folie. Prenons du recul et commençons par une fonction de requête XHR de base utilisant des rappels:Hourra! Cela n'implique rien de très compliqué (comme des en-têtes personnalisés ou des données POST) mais suffit pour nous faire avancer.
Le constructeur de promesses
Nous pouvons construire une promesse comme ceci:
Le constructeur de promesse prend une fonction qui recevra deux arguments (appelons-les
resolve
etreject
). Vous pouvez les considérer comme des rappels, un pour le succès et un pour l'échec. Les exemples sont géniaux, mettons à jourmakeRequest
avec ce constructeur:Maintenant, nous pouvons puiser dans la puissance des promesses, enchaînant plusieurs appels XHR (et le
.catch
déclenchera une erreur sur l'un ou l'autre appel):Nous pouvons encore améliorer cela, en ajoutant à la fois des paramètres POST / PUT et des en-têtes personnalisés. Utilisons un objet options au lieu de plusieurs arguments, avec la signature:
makeRequest
ressemble maintenant à quelque chose comme ceci:Une approche plus globale peut être trouvée chez MDN .
Vous pouvez également utiliser l' API fetch ( polyfill ).
la source
responseType
, l'authentification, les informations d'identification,timeout
… Et lesparams
objets doivent prendre en charge les blobs / bufferviews et lesFormData
instancesxhr.status
etxhr.statusText
en cas d'erreur, car ils sont vides dans ce cas.resolve(xhr.response | xhr.responseText);
Dans la plupart des navigateurs, le repsonse est dans responseText entre-temps.Cela peut être aussi simple que le code suivant.
Gardez à l'esprit que ce code déclenchera le
reject
rappel uniquement lorsqu'ilonerror
est appelé ( erreurs réseau uniquement) et non lorsque le code d'état HTTP signifie une erreur. Cela exclura également toutes les autres exceptions. La gestion de ceux-ci devrait être à vous, OMI.De plus, il est recommandé d'appeler le
reject
callback avec une instance deError
et non l'événement lui-même, mais par souci de simplicité, je l'ai laissé tel quel.Et l'invoquer pourrait être ceci:
la source
xhr.send(requestBody)
Pour tous ceux qui recherchent ceci maintenant, vous pouvez utiliser la fonction de récupération . Il a un assez bon support .
J'ai d'abord utilisé la réponse de @ SomeKittens, mais j'ai ensuite découvert
fetch
que cela le faisait pour moi hors de la boîte :)la source
fetch
fonction, mais GitHub a publié un polyfill .fetch
car il ne prend pas encore en charge l'annulation.Je pense que nous pouvons rendre la réponse supérieure beaucoup plus flexible et réutilisable en ne la faisant pas créer l'
XMLHttpRequest
objet. Le seul avantage de le faire est que nous n'avons pas à écrire nous-mêmes 2 ou 3 lignes de code pour le faire, et cela a l'énorme inconvénient de nous priver de l'accès à de nombreuses fonctionnalités de l'API, comme la définition des en-têtes. Il masque également les propriétés de l'objet d'origine du code censé gérer la réponse (pour les réussites et les erreurs). Nous pouvons donc créer une fonction plus flexible et plus largement applicable en acceptant simplement l'XMLHttpRequest
objet comme entrée et en le transmettant comme résultat .Cette fonction convertit un
XMLHttpRequest
objet arbitraire en promesse, traitant les codes de statut non-200 comme une erreur par défaut:Cette fonction s'intègre très naturellement dans une chaîne de
Promise
s, sans sacrifier la flexibilité de l'XMLHttpRequest
API:catch
a été omis ci-dessus pour simplifier l'exemple de code. Vous devriez toujours en avoir un, et bien sûr nous pouvons:Et la désactivation de la gestion du code d'état HTTP ne nécessite pas beaucoup de changement dans le code:
Notre code d'appel est plus long, mais conceptuellement, il est toujours simple de comprendre ce qui se passe. Et nous n'avons pas besoin de reconstruire toute l'API de requête Web uniquement pour prendre en charge ses fonctionnalités.
Nous pouvons également ajouter quelques fonctions pratiques pour ranger notre code:
Alors notre code devient:
la source
La réponse de jpmc26 est assez proche de la perfection à mon avis. Il présente cependant quelques inconvénients:
POST
-requests à définir le corps de la requête.send
appel crucial est caché dans une fonction.Monkey corrige l'objet xhr résout ces problèmes:
Maintenant, l'utilisation est aussi simple que:
Bien sûr, cela présente un inconvénient différent: la correction des singes nuit aux performances. Cependant, cela ne devrait pas poser de problème en supposant que l'utilisateur attend principalement le résultat du xhr, que la demande elle-même prend des ordres de grandeur plus longs que l'établissement de l'appel et que les demandes xhr ne sont pas envoyées fréquemment.
PS: Et bien sûr, si vous ciblez les navigateurs modernes, utilisez fetch!
PPS: Il a été souligné dans les commentaires que cette méthode modifie l'API standard, ce qui peut prêter à confusion. Pour plus de clarté, on peut appliquer une méthode différente à l'objet xhr
sendAndGetPromise()
.la source
send
appel réel, mais peut également dérouter les lecteurs qui savent que celasend
n'a pas de valeur de retour. L'utilisation d'appels plus explicites indique plus clairement qu'une logique supplémentaire a été invoquée. Ma réponse doit être ajustée pour gérer les arguments àsend
; cependant, il est probablement préférable de l'utiliserfetch
maintenant.