Javascript:返回XMLHttpRequest超出范围
我需要从我的AJAX调用中返回数据
series: [{
data: ( )
为了更新字典data
中的一个键series
,但我的函数retrieve
似乎没有返回我得到的数据。
var myPopulation = {
series: [{
data: (
function() {
function retrieve() {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var obj = JSON.parse(httpRequest.responseText)
console.log(obj.V1, obj.V2, obj.V3, obj.V4);
var data = [],
time = (new Date()).getTime(),
i;
for (i = -60; i <= 0; i++) {
console.log(obj.V2)
data.push({
x: time + i * 60 * 1000,
y: obj.V2
});
}
myPopulation.series[1].data = data
// ???
console.log(data)
}
}
};
httpRequest.open('GET', "/myCall");
httpRequest.send();
}
retrieve();
}()
)
}],
我该怎么做才能将值退出函数并更新data
?
答案 0 :(得分:2)
好吧,既然您使用的是jQuery
标签,我认为我的答案可能有效,我更喜欢按照您的需要这样做,我理解(这是很好的解释所以请阅读代码注释和检查浏览器控制台,这可以在答案的最后找到。
请记住,您无法返回XMLHttpRequest,因为ajax调用是异步的,但您可以强制ajax调用同步,以便从任何函数获取返回语句中的数据或执行其他操作你期待的。但是,强制不是一个好的方法,因为UI会冻结用户,直到从服务器返回响应,你真的不知道需要多少时间(特别是如果你期望大量的数据)退货 - 我知道这不完全是一个指标,但其他因素可能适用。)
希望这会有所帮助,请花点时间阅读以下帖子和用户评论:Reasons not to use native XMLHttpRequest - why is $.ajax mandatory?
现场演示: http://jsfiddle.net/4mbjjfx8/
<强> HTML: 强>
<div id="wrapper">
<div id="loader"></div>
<div id="content"></div>
</div>
<强> 的jQuery 强>
$(function() {
var series = [], // Your series array
loader = $('#loader'), // UI loader sample
request = {}; // Request params
/**
* Set request method, url and data if needed
* In this case I am sending an object with a text property
* that will be returned from jsfiddle "echo" service
*/
request.method = 'GET';
request.url = '/echo/jsonp/';
request.data = {
text: 'Second message returned from "echo" service'
};
// Send ajax call
retrieveData(request, series, handleData);
// Set loading message to UI
loader.html('Loading...');
// Just do some logging to know how process goes
console.log('Populating series for the first time');
/**
* Populate series for the first time, at this point process
* will go on and after the response from server was finally
* done, process will go to the callback (since ajax calls
* are async).
*/
populate(series);
// Just do some logging to know how process goes
console.log('End populating series for the first time');
});
function populate(series) {
var dummy = {
text: 'First message populated over process'
};
// Set dummy object to series array
series.push(dummy);
};
/**
* Used to make ajax call and return data from server
*/
function retrieveData(cfg, series, callback) {
$.ajax({
type: cfg.method,
url: cfg.url,
data: cfg.data
}).done(function(data, status, xhr) {
// Pass args to callback function if defined
if (callback) callback(series, data);
}).fail(function(xhr, status) {
/**
* Pass args to callback function if defined
* At this point, request wasn't success so
* force data arg at callback to be 'null'
*/
if (callback) callback(series, null);
});
};
/**
* Used to handle data returned from server
* Note: Your series array can be modified here since you
* passed it into the callback
*/
function handleData(series, data) {
var loader = $('#loader');
// Just do some logging to know how process goes
console.log('Populating series from server');
// Check if data is defined and not an empty object
if(data && !($.isEmptyObject(data))) {
// Add it to series array
series.push(data);
}
// Set UI loader empty
loader.html('');
// Retrieve series
showData(series);
};
function showData(series) {
var contentDiv = $('#content');
// Loop process and append to UI
for(var i = 0; i < series.length; ++i) {
contentDiv.append(series[i].text + '<br>');
}
};
答案 1 :(得分:1)
你应该把检索功能放在外面。您可以调用检索功能。并且,它将调用ajax。当ajax成功时,它将更新人口数据。像这样。
var myPopulation = {
series: [{
data: undefined
}]
};
function retrieve() {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var obj = JSON.parse(httpRequest.responseText)
console.log(obj.V1, obj.V2, obj.V3, obj.V4);
var data = [],
time = (new Date()).getTime(),
i;
for (i = -60; i <= 0; i++) {
console.log(obj.V2)
data.push({
x: time + i * 60 * 1000,
y: obj.V2
});
}
myPopulation.series[0].data = data
// ???
console.log(data)
}
}
};
httpRequest.open('GET', "/myCall");
httpRequest.send();
}
retrieve();
答案 2 :(得分:1)
假设您在首次定义数组时只是尝试设置myPopulation.series [0] .data的值...
myPopulation.series[1].data = data
......应该......
myPopulation.series[0].data = data;
此外,您的代码的某些部分缺少关闭分号,右括号和/或大括号。请确保以分号结束所有语句,并且您有相同数量的开始和结束(卷曲)括号。
我已使用上述更改测试了您的代码。我做的HTTP请求返回了一个简单的&#34;测试成功&#34;字符串,所以我将处理响应文本结构的代码替换为var data = httpRequest.responeText;
。这很好。当然,这假设在您的情况下处理返回的httpRequest.responeText
的结构的代码是正确的,因为我无法知道您的案例中的responseText是什么样的。如果您收到有关此部分代码的任何错误,我们需要先查看responseText的内容,然后才能为您提供帮助。
答案 3 :(得分:1)
我不判断你是否做得对。我只是向您展示代码的工作版本。
代码中的错误:
注意:修复方法是使XMLHttpRequest同步。
以下是代码的更正版本
var myPopulation = {
series: [{
data: (
function() {
function retrieve() {
var httpRequest = new XMLHttpRequest();
var result = []; //[1] just renamed data to result to avoid confusion
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var obj = JSON.parse(httpRequest.responseText)
console.log(obj.V1, obj.V2, obj.V3, obj.V4);
var time = (new Date()).getTime(),
i;
for (i = -60; i <= 0; i++) {
console.log(obj.V2)
result.push({
x: time + i * 60 * 1000,
y: obj.V2
});
}
//myPopulation.series[1].data = data //[2] commented this as it is not necessary
// ???
console.log(result)
}
}
};
httpRequest.open('GET', "/myCall", false); //[3] Added 3rd argument 'false' to make the call synchronous
httpRequest.send();
return result //[4] to convey the result outside
}
return retrieve(); //[5] added return to set it to the data
}()
)
}],
然而,上述代码未经过测试。这是经过测试的解决方案http://jsfiddle.net/98f9amo8/1/ 由于显而易见的原因,jsfiddle的内容是不同的。
答案 4 :(得分:1)
使用异步代码意味着您必须更改编码方式,因为代码不再自上而下执行。
所以,在你的情况下,你会做类似的事情:
var myPopulation = {series: []};
$.get(..., my_function_that_will_format_the_data_after_they_have_been_received);
...
my_function_that_will_format_the_data_after_they_have_been_received() {
// Do stuff here
var formattedData = ...
myPopulation.series.push(formattedData);
// ONLY NOW, myPopulation is ... populated with data.
// So, whatever you use this for, need to be called here
doMagicWith(myPopulation);
}
...
/// Here, myPopulation is empty. doMagicWith(myPopulation) will fail here.
答案 5 :(得分:0)
我不知道你是如何做到这一点的背景,看到没有jQuery告诉我你希望避免它。
所以无论发生什么事情,电话都需要时间,你需要等待它,无论你需要做什么。加载器可以帮助告诉用户它的处理,但也有其他方法可以做到这一点。共同的因素是,除非你做某种回调,否则当你需要它时,数据不会出现在那里。
所以这是一个想法,或多或少地创建on onload事件。有许多事情需要关注,因此jQuery可能是最完整的,但在这里要保持简单。
window.isLoaded = false;
window.ajaxLoaded = false;
window.onload = function(){
if(window.ajaxLoaded){
onReadyFunction();
}else{
window.isLoaded = true;
}
}
//skipping most of your code, the key part is the retrieve function.
//So its the only part I am going to include in this part.
function retrieve() {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var obj = JSON.parse(httpRequest.responseText)
console.log(obj.V1, obj.V2, obj.V3, obj.V4);
var data = [],
time = (new Date()).getTime(),
i;
for (i = -60; i <= 0; i++) {
console.log(obj.V2)
data.push({
x: time + i * 60 * 1000,
y: obj.V2
});
}
myPopulation.series[1].data = data
// ???
console.log(data)
}
}
//here is my only addition
if(window.isLoaded){
onReadyFunction();
}else{
window.ajaxLoaded = true;
}
};
httpRequest.open('GET', "/myCall");
httpRequest.send();
}
所以我所做的就是在典型的DOM加载中添加另一部分。在初始化JS的其余部分之前等待您需要的数据。这样做可以最大限度地减少应用程序的停机时间(尽管这取决于您尝试获取此数据的位置)。您只需要像这样定义onReadyFunction。
function onReadyFunction(){
//all the rest of your JS here
}
这可以非常简单地扩展和组织,只是一个简单的例子来开始。