Javascript 我如何承诺原生XHR?
我想在我的前端应用程序中使用(本机)承诺来执行XHR请求,但不需要大规模框架的愚蠢 我希望我的xhr返回一个承诺,但这不起作用(给我:Javascript 我如何承诺原生XHR?,javascript,xmlhttprequest,promise,Javascript,Xmlhttprequest,Promise,我想在我的前端应用程序中使用(本机)承诺来执行XHR请求,但不需要大规模框架的愚蠢 我希望我的xhr返回一个承诺,但这不起作用(给我:uncaughttypeerror:promise resolver undefined不是一个函数) 函数makexhrequest(方法、url、完成){ var xhr=new XMLHttpRequest(); open(方法,url); xhr.onload=function(){返回新承诺().resolve();}; xhr.onerror=func
uncaughttypeerror:promise resolver undefined不是一个函数
)
函数makexhrequest(方法、url、完成){
var xhr=new XMLHttpRequest();
open(方法,url);
xhr.onload=function(){返回新承诺().resolve();};
xhr.onerror=function(){return new Promise().reject();};
xhr.send();
}
makexhrequest('GET','http://example.com')
.然后(功能(基准){
控制台日志(基准);
});
我假设您知道如何发出本机XHR请求(您可以重新整理并使用)
因为它还支持xhr.onload
,所以我们可以跳过所有的onReadyStateChange
tom傻瓜。让我们后退一步,用回调开始一个基本的XHR请求函数:
函数makeRequest(方法、url、完成){
var xhr=new XMLHttpRequest();
open(方法,url);
xhr.onload=函数(){
完成(空,xhr.响应);
};
xhr.onerror=函数(){
完成(xhr.响应);
};
xhr.send();
}
//我们这样称呼它:
makeRequest('GET','http://example.com,函数(错误,基准){
if(err){throw err;}
控制台日志(基准);
});
万岁!这并不涉及任何非常复杂的事情(如自定义标题或帖子数据),但足以让我们向前迈进
承诺构造函数
我们可以这样构建一个承诺:
新承诺(功能(解析、拒绝){
//做一些异步的事情
//如果成功,请调用resolve
//如果失败则拒绝
});
promise构造函数接受一个函数,该函数将被传递两个参数(让我们调用它们resolve
和reject
)。你可以把这些看作是回调,一个是成功,一个是失败。示例非常棒,让我们用这个构造函数更新makeRequest
:
函数makeRequest(方法、url){
返回新承诺(功能(解决、拒绝){
var xhr=new XMLHttpRequest();
open(方法,url);
xhr.onload=函数(){
如果(this.status>=200&&this.status<300){
解析(xhr.response);
}否则{
拒绝({
状态:这个状态,
statusText:xhr.statusText
});
}
};
xhr.onerror=函数(){
拒绝({
状态:这个状态,
statusText:xhr.statusText
});
};
xhr.send();
});
}
//例如:
makeRequest('GET','http://example.com')
.然后(功能(基准){
控制台日志(基准);
})
.catch(函数(err){
console.error('Augh,有一个错误!',err.statusText);
});
现在,我们可以利用承诺的力量,链接多个XHR调用(并且,.catch
将触发任一调用的错误):
makeRequest('GET','http://example.com')
.然后(功能(基准){
返回makeRequest('GET',datums.url);
})
.然后(功能(更多数据){
控制台日志(更多数据);
})
.catch(函数(err){
console.error('Augh,有一个错误!',err.statusText);
});
我们可以进一步改进这一点,添加POST/PUT参数和自定义头。让我们使用一个选项对象而不是多个参数,签名为:
{
方法:字符串,
url:String,
参数:字符串|对象,
标题:对象
}
makeRequest
现在看起来像这样:
函数生成请求(opts){
返回新承诺(功能(解决、拒绝){
var xhr=new XMLHttpRequest();
open(opts.method,opts.url);
xhr.onload=函数(){
如果(this.status>=200&&this.status<300){
解析(xhr.response);
}否则{
拒绝({
状态:这个状态,
statusText:xhr.statusText
});
}
};
xhr.onerror=函数(){
拒绝({
状态:这个状态,
statusText:xhr.statusText
});
};
if(选择标题){
Object.key(opts.headers).forEach(function(key){
setRequestHeader(key,opts.headers[key]);
});
}
var params=opts.params;
//如果给了我们一个对象,我们就需要进行字符串化
//如果我们有一个字符串,这将被跳过。
if(params&&typeof params==='object'){
params=Object.keys(params).map(函数(键){
返回encodeURIComponent(键)+'='+encodeURIComponent(参数[key]);
}).加入(“&”);
}
xhr.send(参数);
});
}
//标题和参数是可选的
提出请求({
方法:“GET”,
网址:'http://example.com'
})
.然后(功能(基准){
返回makeRequest({
方法:“POST”,
url:datums.url,
参数:{
分数:9001
},
标题:{
“X-潜意识信息”:“投票表决这个答案”
}
});
})
.catch(函数(err){
console.error('Augh,有一个错误!',err.statusText);
});
可在以下网址找到更全面的方法
或者,您可以使用()。这可以像下面的代码一样简单 请记住,此代码仅在调用
onerror
时(networkerrors only)才会触发reject
回调,而不会在HTTP状态代码表示错误时触发。这也将排除所有其他例外情况。处理这些问题应该由你来决定,国际海事组织
此外,建议使用Error
实例调用reject
回调,而不要调用事件本身,但为了简单起见,我保留了原样
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
});
对于现在搜索此项的任何人,都可以使用此函数。 它有一些相当好的 我首先使用了@SomeKittens的答案,但后来发现
fetch
为我提供了开箱即用的解决方案:)我认为我们可以通过不让它创建XMLHttpRequest来实现更灵活和可重用性
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
function promiseResponse(xhr, failNon2xx = true) {
return new Promise(function (resolve, reject) {
// Note that when we call reject, we pass an object
// with the request as a property. This makes it easy for
// catch blocks to distinguish errors arising here
// from errors arising elsewhere. Suggestions on a
// cleaner way to allow that are welcome.
xhr.onload = function () {
if (failNon2xx && (xhr.status < 200 || xhr.status >= 300)) {
reject({request: xhr});
} else {
resolve(xhr);
}
};
xhr.onerror = function () {
reject({request: xhr});
};
xhr.send();
});
}
Promise.resolve()
.then(function() {
// We make this a separate function to avoid
// polluting the calling scope.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://stackoverflow.com/');
return xhr;
})
.then(promiseResponse)
.then(function(request) {
console.log('Success');
console.log(request.status + ' ' + request.statusText);
});
Promise.resolve()
.then(function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://stackoverflow.com/doesnotexist');
return xhr;
})
.then(promiseResponse)
.catch(function(err) {
console.log('Error');
if (err.hasOwnProperty('request')) {
console.error(err.request.status + ' ' + err.request.statusText);
}
else {
console.error(err);
}
});
Promise.resolve()
.then(function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://stackoverflow.com/doesnotexist');
return xhr;
})
.then(function(xhr) { return promiseResponse(xhr, false); })
.then(function(request) {
console.log('Done');
console.log(request.status + ' ' + request.statusText);
});
function makeSimpleGet(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
return xhr;
}
function promiseResponseAnyCode(xhr) {
return promiseResponse(xhr, false);
}
Promise.resolve(makeSimpleGet('https://stackoverflow.com/doesnotexist'))
.then(promiseResponseAnyCode)
.then(function(request) {
console.log('Done');
console.log(request.status + ' ' + request.statusText);
});
function promisify(xhr, failNon2xx=true) {
const oldSend = xhr.send;
xhr.send = function() {
const xhrArguments = arguments;
return new Promise(function (resolve, reject) {
// Note that when we call reject, we pass an object
// with the request as a property. This makes it easy for
// catch blocks to distinguish errors arising here
// from errors arising elsewhere. Suggestions on a
// cleaner way to allow that are welcome.
xhr.onload = function () {
if (failNon2xx && (xhr.status < 200 || xhr.status >= 300)) {
reject({request: xhr});
} else {
resolve(xhr);
}
};
xhr.onerror = function () {
reject({request: xhr});
};
oldSend.apply(xhr, xhrArguments);
});
}
}
let xhr = new XMLHttpRequest()
promisify(xhr);
xhr.open('POST', 'url')
xhr.setRequestHeader('Some-Header', 'Some-Value')
xhr.send(resource).
then(() => alert('All done.'),
() => alert('An error occured.'));
<script>
self.Promise||document.write("<script src=/path/to/promise/polyfill.js><\/script>");
</script>
function send_request(xhr, data, timeout) {
return new Promise(function (resolve, reject) {
var s, p, i;
if (data && data.constructor==Object) {// serialize object
s = "_="+(new Date).getTime();
for (p in data) if (data.hasOwnProperty(p)) {
if (!data[p] || data[p].constructor!=Array) {
data[p] = [data[p]]
}
for (i=0; i<data[p].length; i++) {
s+= "&"+encodeuricomponent(p)+"="+encodeuricomponent(data[p][i]);
}
}
data = s;
}
xhr.onreadystatechange = function() {
if (xhr.readyState==4) {
resolve(xhr);
}
}
xhr.send(data);
if (timeout) {
settimeout(function() {
reject("timeout");
xhr.abort();
}, timeout);// milliseconds until timeout
}
});
}
xhr = new XMLHttpRequest();
xhr.open("GET", "/some/file", true);
send_request(xhr).then(function(xhr) {
if (xhr.status>=200 || xhr.status<400) {
//success
alert(xhr.responseText);
}
else {
return Promise.reject(xhr.statusText? xhr.status+" "+xhr.statusText: "error");
}
})
<!--[if lt IE 7]>
<script>
// This is just an example. Use at your own risk.
function XMLHttpRequest() {
try {
return new ActiveXObject("Msxml2.XMLHTTP.6.0")
}
catch (e) {
return new ActiveXObject("Msxml2.XMLHTTP.3.0")
}
}
</script>
<![endif]-->