我如何promisative本机XHR?

我想在我的前端应用程序中使用(本机)promise来执行XHR请求,但是没有一个庞大的框架。

我想我的xhr返回一个承诺,但这是行不通的(给我: 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请求(你可以在这里和这里刷新)

由于任何支持本地承诺的浏览器也会支持xhr.onload ,所以我们可以跳过所有的onReadyStateChange 。 让我们退后一步,使用callback函数开始一个基本的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数据),但足以让我们前进。

承诺构造函数

我们可以这样构build一个承诺:

 new Promise(function (resolve, reject) { // Do some Async stuff // call resolve if it succeeded // reject if it failed }); 

承诺构造函数接受一个函数,将传递两个参数(让我们称它们resolvereject )。 你可以把这些看作是callback,一个是成功,一个是失败。 例子很棒,让我们用这个构造函数更新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可以find更全面的方法。

或者,您可以使用获取API ( polyfill )。

这可以像下面的代码一样简单。

请记住,此代码只会在调用onerror (仅限networking错误)时触发rejectcallback,而不会在HTTP状态代码表示错误时触发rejectcallback。 这也将排除所有其他例外。 处理这些应该由你决定,国际海事组织。

此外,build议使用Error实例调用rejectcallback,而不是事件本身,但为了简单起见,我保持原样。

 function request(method, url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.onload = resolve; xhr.onerror = reject; xhr.send(); }); } 

并援引它可能是这样的:

 request('GET', 'http://google.com') .then(function (e) { console.log(e.target.response); }, function (e) { // handle errors }); 

对于任何人现在search这个,你可以使用获取function。 它有一些相当不错的支持 。

我已经使用@ SomeKittens的答案,但后来发现fetch这对我来说是开箱即用:)