Ich möchte (native) Versprechen in meiner Frontend-App verwenden, um XHR-Anfragen auszuführen, aber ohne die Dummheit eines massiven Frameworks.
Ich mag , dass mein xhr ein Versprechen zurückzukehren , aber das funktioniert nicht (was mir: 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
quelle
quelle
Antworten:
Ich gehe davon aus, dass Sie wissen, wie man eine native XHR-Anfrage stellt (Sie können hier und hier auffrischen ).
Da jeder Browser, der native Versprechen unterstützt
xhr.onload
, dies auch unterstützt , können wir alleonReadyStateChange
Dummheiten überspringen . Machen wir einen Schritt zurück und beginnen mit einer grundlegenden XHR-Anforderungsfunktion unter Verwendung von Rückrufen:Hurra! Dies beinhaltet nichts schrecklich Kompliziertes (wie benutzerdefinierte Header oder POST-Daten), reicht aber aus, um uns vorwärts zu bringen.
Der Versprechenskonstrukteur
Wir können ein Versprechen wie folgt konstruieren:
Der Versprechen-Konstruktor übernimmt eine Funktion, der zwei Argumente übergeben werden (nennen wir sie
resolve
undreject
). Sie können sich diese als Rückrufe vorstellen, einen für den Erfolg und einen für den Misserfolg. Beispiele sind fantastisch, lassen Sie unsmakeRequest
mit diesem Konstruktor aktualisieren :Jetzt können wir die Kraft von Versprechungen nutzen und mehrere XHR-Aufrufe verketten (und
.catch
bei beiden Anrufen wird ein Fehler ausgelöst):Wir können dies noch weiter verbessern, indem wir sowohl POST / PUT-Parameter als auch benutzerdefinierte Header hinzufügen. Verwenden wir ein Optionsobjekt anstelle mehrerer Argumente mit der Signatur:
makeRequest
sieht jetzt ungefähr so aus:Einen umfassenderen Ansatz finden Sie bei MDN .
Alternativ können Sie die Abruf-API ( Polyfill ) verwenden.
quelle
responseType
, Authentifizierung, Anmeldeinformationen usw. hinzufügen.timeout
Undparams
Objekte sollten Blobs / Pufferansichten undFormData
Instanzen unterstützenxhr.status
undxhr.statusText
auf Fehler, da sie in diesem Fall leer sind.resolve(xhr.response | xhr.responseText);
In den meisten Browsern ist die Antwort in der Zwischenzeit in responseText.Dies kann so einfach sein wie der folgende Code.
Beachten Sie, dass dieser Code den
reject
Rückruf nur auslöst, wenn eronerror
aufgerufen wird (nur Netzwerkfehler ) und nicht, wenn der HTTP-Statuscode einen Fehler anzeigt. Dies schließt auch alle anderen Ausnahmen aus. Der Umgang mit diesen sollte bei Ihnen liegen, IMO.Außerdem wird empfohlen, den
reject
Rückruf mit einer Instanz vonError
und nicht mit dem Ereignis selbst aufzurufen , aber der Einfachheit halber habe ich es so belassen, wie es ist.Und es aufzurufen könnte sein:
quelle
xhr.send(requestBody)
Für alle, die jetzt danach suchen, können Sie die Abruffunktion verwenden. Es hat einige ziemlich gute Unterstützung .
Ich habe zuerst die Antwort von @ SomeKittens verwendet, dann aber festgestellt,
fetch
dass dies für mich sofort erledigt ist :)quelle
fetch
Funktion nicht, aber GitHub hat eine Polyfüllung veröffentlicht .fetch
da es die Stornierung noch nicht unterstützt.Ich denke, wir können die Top-Antwort viel flexibler und wiederverwendbarer machen, indem wir das
XMLHttpRequest
Objekt nicht erstellen lassen . Der einzige Vorteil dabei ist, dass wir nicht zwei oder drei Codezeilen selbst schreiben müssen, um dies zu tun, und es hat den enormen Nachteil, dass wir nicht mehr auf viele Funktionen der API zugreifen können, z. B. das Setzen von Headern. Außerdem werden die Eigenschaften des Originalobjekts vor dem Code ausgeblendet, der die Antwort verarbeiten soll (sowohl für Erfolge als auch für Fehler). So können wir eine flexiblere und umfassendere Funktion erstellen, indem wir dasXMLHttpRequest
Objekt einfach als Eingabe akzeptieren und als Ergebnis übergeben .Diese Funktion konvertiert ein beliebiges
XMLHttpRequest
Objekt in ein Versprechen und behandelt Nicht-200-Statuscodes standardmäßig als Fehler:Diese Funktion passt ganz natürlich in eine Kette von
Promise
s, ohne die Flexibilität derXMLHttpRequest
API zu beeinträchtigen:catch
wurde oben weggelassen, um den Beispielcode einfacher zu halten. Sie sollten immer eine haben, und natürlich können wir:Das Deaktivieren der Verarbeitung des HTTP-Statuscodes erfordert keine großen Änderungen am Code:
Unser Anrufcode ist länger, aber konzeptionell ist es immer noch einfach zu verstehen, was los ist. Und wir müssen nicht die gesamte Webanforderungs-API neu erstellen, nur um ihre Funktionen zu unterstützen.
Wir können auch einige praktische Funktionen hinzufügen, um unseren Code aufzuräumen:
Dann wird unser Code:
quelle
Die Antwort von jpmc26 ist meiner Meinung nach nahezu perfekt. Es hat jedoch einige Nachteile:
POST
-requests nicht, den Anforderungshauptteil festzulegen.send
Aufruf in einer Funktion verborgen ist.Das Patchen des xhr-Objekts durch Affen behebt folgende Probleme:
Jetzt ist die Verwendung so einfach wie:
Dies bringt natürlich einen anderen Nachteil mit sich: Das Patchen von Affen beeinträchtigt die Leistung. Dies sollte jedoch kein Problem sein, vorausgesetzt, der Benutzer wartet hauptsächlich auf das Ergebnis von xhr, die Anforderung selbst dauert um Größenordnungen länger als das Einrichten des Anrufs, und xhr-Anforderungen werden nicht häufig gesendet.
PS: Und wenn Sie auf moderne Browser abzielen, verwenden Sie natürlich fetch!
PPS: In den Kommentaren wurde darauf hingewiesen, dass diese Methode die Standard-API ändert, was verwirrend sein kann. Zur besseren Übersicht könnte man eine andere Methode auf das xhr-Objekt patchen
sendAndGetPromise()
.quelle
send
Aufruf, kann aber auch Leser verwirren, die wissen, dass ersend
keinen Rückgabewert hat. Durch die Verwendung expliziterer Aufrufe wird klarer, dass zusätzliche Logik aufgerufen wurde. Meine Antwort muss angepasst werden, um Argumente zu verarbeitensend
; Es ist jedoch wahrscheinlich besser, esfetch
jetzt zu verwenden .