ฉันสมมติว่าคุณรู้วิธีสร้างคำขอ XHR แบบดั้งเดิม (คุณสามารถแปรงที่นี่และที่นี่ )
เนื่องจากเบราว์เซอร์ใด ๆ ที่สนับสนุนคำสัญญาดั้งเดิมจะรองรับxhr.onload
เราจึงสามารถข้ามonReadyStateChange
tomfoolery ทั้งหมดได้ ลองย้อนกลับไปและเริ่มต้นด้วยฟังก์ชั่นการร้องขอ XHR ขั้นพื้นฐานโดยใช้การเรียกกลับ:
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);
});
เย่! สิ่งนี้ไม่เกี่ยวข้องกับสิ่งที่ซับซ้อนมาก (เช่นส่วนหัวที่กำหนดเองหรือข้อมูล POST) แต่ก็เพียงพอที่จะทำให้เราก้าวไปข้างหน้า
คอนสตรัคสัญญา
เราสามารถสร้างสัญญาเช่นนั้นได้:
new Promise(function (resolve, reject) {
// Do some Async stuff
// call resolve if it succeeded
// reject if it failed
});
คอนสตรัคสัญญาใช้ฟังก์ชั่นที่จะถูกส่งผ่านสองอาร์กิวเมนต์ (เรียกว่าพวกมันresolve
และreject
) คุณสามารถคิดว่าสิ่งเหล่านี้เป็นการเรียกกลับหนึ่งรายการสำหรับความสำเร็จและอีกหนึ่งสำหรับความล้มเหลว ตัวอย่างน่ากลัวมาอัปเดตmakeRequest
กับตัวสร้างนี้:
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);
});
ตอนนี้เราสามารถแตะที่พลังแห่งสัญญาผูกสาย XHR หลายสาย (และ.catch
จะทำให้เกิดข้อผิดพลาดในการโทรทั้งสอง):
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);
});
เราสามารถปรับปรุงสิ่งนี้ได้อีกโดยเพิ่มทั้ง POST / PUT และส่วนหัวที่กำหนดเอง ลองใช้อ็อบเจกต์อ็อพชั่นแทนอาร์กิวเมนต์หลายตัวพร้อมลายเซ็น:
{
method: String,
url: String,
params: String | Object,
headers: Object
}
makeRequest
ตอนนี้ดูเหมือนว่า:
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);
});
วิธีการที่ครอบคลุมมากขึ้นสามารถพบได้ที่MDN
หรือคุณสามารถใช้API การดึงข้อมูล ( polyfill )