我写了下面这段代码。 makeRequest
被调用,我想在xhr状态为0时重试此问题。问题是我无法解析正确的promise,重试逻辑在第n次尝试中获取正确的响应但未能传播到调用方法。
如何解决此问题。
var makeRequest = function(method, urlToBeCalled, payload) {
var deferred = $q.defer();
var xhr = new XMLHttpRequest();
xhr.open(method, encodeURI(urlToBeCalled), true);
setHttpRequestHeaders(xhr); // set headers
var response;
xhr.onload = function() {
if (xhr.status === 200 && xhr.readyState === 4 && xhr.getResponseHeader('content-type') !==
'text/html') {
try {
response = JSON.parse(xhr.response);
deferred.resolve(response);
} catch (e) {
deferred.reject(e);
}
} else if (xhr.status === 0) {
// retry here;
deferred.resolve(makeRequest(method, urlToBeCalled, payload));
} else {
try {
response = JSON.parse(xhr.response);
deferred.reject(response);
} catch (e) {
deferred.reject(xhr.response);
}
}
};
xhr.onerror = function() {
deferred.reject(xhr.response);
};
xhr.send(payload);
return deferred.promise;
};
答案 0 :(得分:1)
以下是我接近它的方法(参见***
评论):
var makeRequest = function(method, urlToBeCalled, payload) {
var deferred = $q.defer();
var retries = 4; // *** Counter
run(); // *** Call the worker
return deferred.promise;
// *** Move the actual work to its own function
function run() {
var xhr = new XMLHttpRequest();
xhr.open(method, encodeURI(urlToBeCalled), true);
setHttpRequestHeaders(xhr);
xhr.onload = function() {
if (xhr.status === 200 && xhr.readyState === 4 && xhr.getResponseHeader('content-type') !== 'text/html') {
try {
response = JSON.parse(xhr.response);
deferred.resolve(response);
} catch (e) {
deferred.reject(e);
}
} else if (xhr.status === 0) {
// retry
if (retries--) { // *** Recurse if we still have retries
run();
} else {
// *** Out of retries
deferred.reject(e);
}
} else {
// *** See note below, probably remove this
try {
response = JSON.parse(xhr.response);
deferred.reject(response);
} catch (e) {
deferred.reject(xhr.response);
}
}
};
xhr.onerror = function() {
deferred.reject(xhr.response);
};
xhr.send(payload);
}
};
附注:您的初始if
正文和最终else
的内容似乎相同。我想我会改写整个onload
:
xhr.onload = function() {
if (xhr.readyState === 4) {
// It's done, what happened?
if (xhr.status === 200) {
if (xhr.getResponseHeader('content-type') !== 'text/html') {
try {
response = JSON.parse(xhr.response);
deferred.resolve(response);
} catch (e) {
deferred.reject(e);
}
} else {
// Something went wrong?
deferred.reject(e);
}
} else if (xhr.status === 0) {
// retry
if (retries--) { // *** Recurse if we still have retries
run();
} else {
// *** Out of retries
deferred.reject(e);
}
}
}
};
重新评论:
这确实解决了我当前的问题,但是有没有办法解决添加到调用堆栈的所有承诺,如果其中任何一个被解析?
是的:要使用Angular的$q
(我假设你正在使用的是),你可以将你从延迟对象的递归调用中获得的承诺传递给resolve
:由于这是一个承诺,延期将等待它根据承诺的作用得到解决和解决或拒绝。如果您在链中的每个级别执行此操作,则解决方案会在链中向上运行:
angular.module("mainModule", []).controller(
"mainController",
function($scope, $q, $http) {
test(true).then(function() {
test(false);
});
function test(flag) {
log(flag ? "Testing resolved" : "Testing rejected");
return recursive(3, flag)
.then(function(arg) {
log("Resolved with", arg);
})
.catch(function(arg) {
log("Rejected with", arg);
});
}
function recursive(count, flag) {
log("recursive(" + count + ", " + flag + ") called");
var d = $q.defer();
setTimeout(function() {
if (count <= 0) {
// Done, settle
if (flag) {
log("Done, resolving with " + count);
d.resolve(count);
} else {
log("Done, rejecting with " + count);
d.reject(count);
}
} else {
// Not done, resolve with promise from recursive call
log("Not done yet, recursing with " + (count - 1));
d.resolve(recursive(count - 1, flag));
}
}, 0);
return d.promise;
}
}
);
function log() {
var p = document.createElement('pre');
p.appendChild(
document.createTextNode(
Array.prototype.join.call(arguments, " ")
)
);
document.body.appendChild(p);
}
pre {
margin: 0;
padding: 0;
}
<div ng-app="mainModule">
<div ng-controller="mainController"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
您可以使用JavaScript自己的承诺做同样的事情:
test(true).then(function() {
test(false);
});
function test(flag) {
log(flag ? "Testing resolved" : "Testing rejected");
return recursive(3, flag)
.then(function(arg) {
log("Resolved with", arg);
})
.catch(function(arg) {
log("Rejected with", arg);
});
}
function recursive(count, flag) {
log("recursive(" + count + ", " + flag + ") called");
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (count <= 0) {
// Done, resolve with value
if (flag) {
log("Done, resolving with " + count);
resolve(count);
} else {
log("Done, rejecting with " + count);
reject(count);
}
} else {
// Not done, resolve with promise
// from recursive call
log("Not done yet, recursing with " + (count - 1));
resolve(recursive(count - 1, flag));
}
}, 0);
});
}
function log() {
var p = document.createElement('pre');
p.appendChild(
document.createTextNode(
Array.prototype.join.call(arguments, " ")
)
);
document.body.appendChild(p);
}
pre {
margin: 0;
padding: 0;
}