Javascript:返回XMLHttpRequest超出范围

时间:2014-08-22 07:23:30

标签: javascript jquery ajax xmlhttprequest

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

6 个答案:

答案 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)

我不判断你是否做得对。我只是向您展示代码的工作版本。

代码中的错误:

  1. 您的意思是设置&#34;功能的结果&#34;数据,但你的功能首先没有返回任何内容。
  2. XMLHttpRequest是异步的,所以即使你返回也不会有数据集,只是因为在完成http请求设置回调后外部函数退出。
  3. 注意:修复方法是使XMLHttpRequest同步。

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests

    以下是代码的更正版本

    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
}

这可以非常简单地扩展和组织,只是一个简单的例子来开始。