Tôi giả sử bạn biết cách tạo một yêu cầu XHR riêng (bạn có thể xem ở đây và đây )
Vì bất kỳ trình duyệt nào hỗ trợ lời hứa riêng cũng sẽ hỗ trợ xhr.onload
, chúng tôi có thể bỏ qua tất cả các onReadyStateChange
tomfoolery. Hãy lùi lại một bước và bắt đầu với chức năng yêu cầu XHR cơ bản bằng cách sử dụng các cuộc gọi lại:
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);
});
Tiếng hoan hô! Điều này không liên quan đến bất kỳ điều gì phức tạp khủng khiếp (như tiêu đề tùy chỉnh hoặc dữ liệu POST) nhưng đủ để khiến chúng tôi tiến lên.
Người xây dựng lời hứa
Chúng ta có thể xây dựng một lời hứa như vậy:
new Promise(function (resolve, reject) {
// Do some Async stuff
// call resolve if it succeeded
// reject if it failed
});
Hàm tạo hứa hẹn có một hàm sẽ được truyền hai đối số (hãy gọi chúng resolve
và reject
). Bạn có thể nghĩ về những điều này như cuộc gọi lại, một cho thành công và một cho thất bại. Các ví dụ thật tuyệt vời, hãy cập nhật makeRequest
với hàm tạo này:
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);
});
Bây giờ chúng ta có thể khai thác sức mạnh của lời hứa, thực hiện nhiều cuộc gọi XHR (và .catch
sẽ kích hoạt lỗi cho một trong hai cuộc gọi):
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);
});
Chúng tôi có thể cải thiện điều này hơn nữa, thêm cả thông số POST / PUT và tiêu đề tùy chỉnh. Chúng ta hãy sử dụng một đối tượng tùy chọn thay vì nhiều đối số, với chữ ký:
{
method: String,
url: String,
params: String | Object,
headers: Object
}
makeRequest
bây giờ trông giống như thế này:
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);
});
Một cách tiếp cận toàn diện hơn có thể được tìm thấy tại MDN .
Ngoài ra, bạn có thể sử dụng API tìm nạp ( polyfill ).