我想在我的前端应用程序中使用(本机)promise来执行XHR请求,但没有大型框架的所有功能。
我希望我的XHR返回的希望,但是,这并不工作(给我:Uncaught TypeError: Promise resolver undefined is not a function)
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); });
我假设您知道如何发出本机XHR请求
由于任何支持本机Promise的浏览器也将支持xhr.onload,因此我们可以跳过所有的onReadyStateChangetomfoolery。让我们退后一步,从使用回调的基本XHR请求函数开始:
xhr.onload
onReadyStateChange
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 });
promise构造函数采用一个函数,该函数将传递两个参数(我们称它们为resolve和reject)。您可以将它们视为回调,一个代表成功,另一个代表失败。示例很棒,让我们makeRequest使用此构造函数进行更新:
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); });
现在,我们可以利用promise的功能,将多个XHR调用链接起来(并且.catch将在每次调用中触发错误):
.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参数和自定义标头。让我们使用带有签名的options对象而不是多个参数:
{ 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); });
。