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 alle onReadyStateChange
Dummheiten überspringen . Machen wir einen Schritt zurück und beginnen mit einer grundlegenden XHR-Anforderungsfunktion unter Verwendung von Rückrufen:
function makeRequest (method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
done(null, xhr.response);
};
xhr.onerror = function () {
done(xhr.response);
};
xhr.send();
}
// And we'd call it as such:
makeRequest('GET', 'http://example.com', function (err, datums) {
if (err) { throw err; }
console.log(datums);
});
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:
new Promise(function (resolve, reject) {
// Do some Async stuff
// call resolve if it succeeded
// reject if it failed
});
Der Versprechen-Konstruktor übernimmt eine Funktion, der zwei Argumente übergeben werden (nennen wir sie resolve
und reject
). 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 uns makeRequest
mit diesem Konstruktor aktualisieren :
function makeRequest (method, url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
// Example:
makeRequest('GET', 'http://example.com')
.then(function (datums) {
console.log(datums);
})
.catch(function (err) {
console.error('Augh, there was an error!', err.statusText);
});
Jetzt können wir die Kraft von Versprechungen nutzen und mehrere XHR-Aufrufe verketten (und .catch
bei beiden Anrufen wird ein Fehler ausgelöst):
makeRequest('GET', 'http://example.com')
.then(function (datums) {
return makeRequest('GET', datums.url);
})
.then(function (moreDatums) {
console.log(moreDatums);
})
.catch(function (err) {
console.error('Augh, there was an error!', err.statusText);
});
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:
{
method: String,
url: String,
params: String | Object,
headers: Object
}
makeRequest
sieht jetzt ungefähr so aus:
function makeRequest (opts) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(opts.method, opts.url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
if (opts.headers) {
Object.keys(opts.headers).forEach(function (key) {
xhr.setRequestHeader(key, opts.headers[key]);
});
}
var params = opts.params;
// We'll need to stringify if we've been given an object
// If we have a string, this is skipped.
if (params && typeof params === 'object') {
params = Object.keys(params).map(function (key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
}
xhr.send(params);
});
}
// Headers and params are optional
makeRequest({
method: 'GET',
url: 'http://example.com'
})
.then(function (datums) {
return makeRequest({
method: 'POST',
url: datums.url,
params: {
score: 9001
},
headers: {
'X-Subliminal-Message': 'Upvote-this-answer'
}
});
})
.catch(function (err) {
console.error('Augh, there was an error!', err.statusText);
});
Einen umfassenderen Ansatz finden Sie bei MDN .
Alternativ können Sie die Abruf-API ( Polyfill ) verwenden.