Saya berasumsi Anda tahu cara membuat permintaan XHR asli (Anda dapat memoles di sini dan di sini )
Karena browser apa pun yang mendukung janji asli juga akan mendukung xhr.onload
, kami dapat melewati semua onReadyStateChange
tindakan buruk tersebut. Mari kita mundur selangkah dan mulai dengan fungsi permintaan XHR dasar menggunakan callback:
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);
});
Hore! Ini tidak melibatkan sesuatu yang sangat rumit (seperti header khusus atau data POST) tetapi cukup untuk membuat kita bergerak maju.
Konstruktor janji
Kita bisa membuat janji seperti ini:
new Promise(function (resolve, reject) {
// Do some Async stuff
// call resolve if it succeeded
// reject if it failed
});
Konstruktor janji mengambil fungsi yang akan melewati dua argumen (sebut saja resolve
dan reject
). Anda dapat menganggap ini sebagai panggilan balik, satu untuk kesuksesan dan satu untuk kegagalan. Contohnya luar biasa, mari perbarui makeRequest
dengan konstruktor ini:
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);
});
Sekarang kita dapat memanfaatkan kekuatan janji, merantai beberapa panggilan XHR (dan keinginan .catch
akan memicu kesalahan pada salah satu panggilan):
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);
});
Kami dapat meningkatkan ini lebih jauh, menambahkan params POST / PUT dan header kustom. Mari kita gunakan objek opsi alih-alih beberapa argumen, dengan tanda tangan:
{
method: String,
url: String,
params: String | Object,
headers: Object
}
makeRequest
sekarang terlihat seperti ini:
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);
});
Pendekatan yang lebih komprehensif dapat ditemukan di MDN .
Atau, Anda bisa menggunakan API pengambilan ( polyfill ).