开发者

Scoping Out the Javascript Function Scope Problem

It's very clear I don't understand how functions are scoped in Javascri开发者_运维知识库pt. Here's the latest example:

function riseData() { 
    var jsonResult;
    $.ajax({
        success: function(data, textStatus, jqXHR){
            jsonResult = jqXHR.responseText;
            alert("Inside: " + jsonResult);
        },          
        error: function (jqXHR, textStatus, errorThrown) {  
            $('#errLog').append('<br>Status: ' + qXHR.statusText);                  
        }
    });
    return jsonResult;
}

$(document).ready(function(){
    var intervalID = setInterval('UTCclock()',100); 
    alert("Outside: " + riseData());                            
});

When I execute this, the "Inside" alert functions properly, but the "Outside" alert displays "undefined", even though riseData() is obviously defined only a few lines earlier. There is a $.ajaxSetup earlier in the code which defines the parameters for the ajax call. The ajax call successfully returns the requested data in the "Inside" alert.

I just haven't the slightest clue how to make the necessary data (jqXHR.responseText) available to other parts of the script.

Can anyone point me at a "Javascript Scoping for Dummies" how-to that addresses this issue?


Your example is scoped just fine. Your problem is you don't understand the implications of how JavaScript is mainly asynchronous.

Let me go through your example to show you.

  1. Your document ready handler runs.
  2. It calls riseData.
  3. riseData declares a variable, jsonResult.
  4. riseData calls $.ajax, which schedules an AJAX request to be done, but the response will happen later.
  5. Since $.ajax is usually non-blocking/asynchronous, riseData continues and returns jsonResult. Since jsonResult has not been assigned yet because the AJAX request has not completed, the default value of undefined is returned.
  6. In the document ready handler, you end up with alert("Outside: "+undefined);.

An event loop to a few milliseconds later, this happens:

  1. The AJAX request is completed. jQuery forwards this on to your callback.
  2. jsonResult is set, but riseData has already returned.
  3. The alert inside riseData alerts with the new data, after the document ready handler has already alerted undefined.

There are two solutions to this problem. The first solution is simple, but often results in a worse user experience. This solution is to add the async: false option to $.ajax. This makes $.ajax block and freeze the browser.

The second solution is to adopt an asynchronous style for almost everything. That means making riseData accept a callback and calling it inside the AJAX response handler. Here's your code transformed with this method:

function riseData(callback) { 
    $.ajax({
        success: function(data, textStatus, jqXHR){
            var jsonResult = jqXHR.responseText;
            alert("Inside: " + jsonResult);
            callback(jsonResult);
        },          
        error: function (jqXHR, textStatus, errorThrown) {  
            $('#errLog').append('<br>Status: ' + qXHR.statusText);                  
        }
    });
}

$(document).ready(function(){
    //var intervalID = setInterval('UTCclock()',100); 
    // Unrelated, but it's better to pass a
    // function into setInterval than a string.
    var intervalID = setInterval(UTCclock, 100);
    riseData(function(jsonResult) {
        alert("Outside: " + jsonResult);
    });
});


This is only partially a scope issue. Your ajax call is asynchronous, so the riseData() function returns a value before the ajax call is executed. Try setting your variable outside the method.

var jsonResult;

function riseData() { 

    $.ajax({
...

jsonResult should not only be available in riseData(), but also out. However, you'll still have the issue of exactly when it gets populated.

A link for a little more explanation:

What is the scope of variables in JavaScript?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜