我目前正在尝试编写一个简单的应用程序,它通过多个异步xhr请求从服务器请求数据。响应在每个请求的onreadystatechanged回调中处理。
目前,如果我异步执行超过10个请求,我开始从请求回调中获取错误的数据,又名:
book 1: abc --> correct
book 2: efg --> correct
book 3: efg --> wrong
book 4: kjl --> correct
我回到了onreadystatehandler,甚至在这里请求对象包含错误的数据(req.responseText)。 网址(req.responseURL)是正确的,因为请求的每个网址都会被回调一次,只是输入了错误的数据。
所以我在浏览器devtools看了一下我收到的回复,以确认服务器确实提供了正确的数据,情况就是这样。
老实说,我没有任何关于如何解决这个问题的想法,因为服务器正在使用正确的数据进行响应,但请求回调只是"使用"错误的,即使有正确的网址。
这就是我尝试实现它的方式:
var sendRequest = function(url, callback){
var req = new XMLHttpRequest();
req.overrideMimeType('text/plain');
req.open("GET", url, true);
if(callback) {
req.onreadystatechange = (function(req,callback){
return function() {
if(req.readyState == 4) {
if(req.status == 200 || req.status == 304) {
var response;
try {
response = JSON.parse(req.responseText);
} catch(error) {
callback(undefined, req.responseText);
return;
}
if(response.error)
callback(response.error, response);
else
callback(undefined, response);
}else{
callback("Error", req.responseText)
}
}
};
})(req,callback);
}
req.send(params);
}
以下是我用于发送请求的代码示例。
var booksToLoad = 0;
for(var i = 0; i < libraries.length; i++) {
(function(i) {
sendRequest('/LibraryList?'+'Id='+libraries[i]._id, function(err, response) {
libraries[i] = response.library;
booksToload += libraries[i].books.length;
for(var j=0; j < libraries[i].books.length; j++) {
(function (i, j) {
sendRequest('/BookList?'+'Id='+libraries[i].books[j]._id, function (err, response) {
libraries[i].books[j].pages = response.pages;
--booksToLoad;
if(booksToLoad == 0)
return;
});
})(i, j);
}
});
})(i);
}
我尝试过的事情:
如前所述,我很困惑的事实是来自服务器的数据很好并且使用正确的req.responseURL调用回调但是错误的数据(不是从响应中的url中获取)。
感谢您的帮助,我在这里不知所措......
Maggistro
编辑:我有点放弃,并决定是不好的设计,无论如何发送这个数量的xhr请求。所以我将这些请求捆绑在一起(整个库,包含书籍+页面)。这样,如果软件包稍后变大,我就不得不管理我所请求的数据(我有完全控制权),而不是浏览器允许的请求数量。
不知道这是不是一个好主意,但我不能在这个问题上花更多的时间。 仍然想确切知道导致此行为的原因以供将来参考。
感谢您的时间,
Maggistro
答案 0 :(得分:1)
试试这个:
function fetchLibrary(i){
sendRequest('/LibraryList?Id='+libraries[i]._id, function(err, response) {
libraries[i] = response.library;
for(var j=0; j < libraries[i].books.length; j++)
fetchBooks(i,j);
});
}
function fetchBooks(i,j){
sendRequest('/BookList?Id='+libraries[i].books[j]._id, function (err, response) {
libraries[i].books[j].pages = response.pages;
});
}
for(var i = 0; i < libraries.length; i++) {
fetchLibrary(i);
}
并且,使用网络选项卡确保正在发送的请求确实返回正确的结果。如果他们不这样做(检查响应),请修复服务器端获取组件。
==========
好的,这里是服务器端和客户端组件的完全测试和功能示例。使用它作为参考:
服务器端(service.php):
<?php
$libraries = [
["id" => 1, "name" => "foo"],
["id" => 2, "name" => "bar"],
["id" => 3, "name" => "baz"]
];
$books = [
["library_id" => 1, "id" => 1, "pages" => 10],
["library_id" => 1, "id" => 2, "pages" => 11],
["library_id" => 1, "id" => 3, "pages" => 12],
["library_id" => 2, "id" => 4, "pages" => 13],
["library_id" => 2, "id" => 4, "pages" => 14],
["library_id" => 2, "id" => 5, "pages" => 15],
["library_id" => 3, "id" => 6, "pages" => 16],
["library_id" => 3, "id" => 7, "pages" => 17],
["library_id" => 3, "id" => 8, "pages" => 18]
];
header("Content-type: application/json;encoding=utf-8");
if (!isset($_REQUEST["request_id"])){
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
header($protocol . ' 500 Error - Specify Request ID');
exit;
}
$request_id = $_REQUEST["request_id"];
$library_id = isset($_REQUEST["library_id"])?$_REQUEST["library_id"]:null;
$ret = [];
if ($library_id){
// fetch list of books for the library_id
foreach ($books as $book){
if ($book["library_id"] == $library_id){
$ret[] = $book;
}
}
} else {
// fetch list of libraries
$ret = $libraries;
}
print_r(json_encode(["request_id" => $request_id, "result" => $ret], JSON_PRETTY_PRINT));
客户方:
<script>
function r(url, callback){
var req = new XMLHttpRequest();
req.responseType = "json";
url += url.match(/\?/)?"&":"?";
var request_id = new Date().getTime();
url += "request_id=" + request_id;
req.open("GET", url, true);
req.onreadystatechange = function(){
if (req.readyState == 4) {
status = req.status;
if (status == 200) {
console.log("URL " + url + " received", req.response);
callback(req.response, request_id);
} else {
window.alert("Problem with request " + url);
console.error(url + " failed. Status: " + status);
console.log(req.response);
}
}
}
req.send();
}
function fetchLibraries(){
r("service.php", function(data, id){
for (var x in data.result){
fetchBooks(data.result[x]);
}
});
}
function fetchBooks(library){
var e = document.createElement("p");
document.body.appendChild(e);
e.innerHTML = "loading " + library.id;
r("service.php?library_id=" + library.id, function(data){
e.innerHTML = "";
for (var x in data.result){
var book = data.result[x];
e.innerHTML += "Book: " + book.id + ", pages: " + book.pages + "<br>";
}
});
}
fetchLibraries();
</script>
经过全面测试,效果非常好。