Undefined Indexes in Array after Asynchronous Requests

前端 未结 1 2011
余生分开走
余生分开走 2021-01-20 20:38

I\'m having some difficulty with an array that is (outside of an asynchronous call) perfectly well-defined but when I call its indices inside an asynch request (e.g. $.getJS

相关标签:
1条回答
  • 2021-01-20 21:28

    The problem is that the callback function happens some time later when the ajax function completes. By then, the array index has advanced to the end of your for loop (thus it points off the end of the array) to an undefined value. The array is still there, but your index has been changed by the time the completion function is called.

    The technique usually used to get the index into the success handler is to capture it in a function closure where it gets captured for use in the completion function.

    You can create a closure that captures the index value by replacing your success handler with this:

    (function(index) {
        return function(dataJSON2) {
            resultArray = dataJSON2['data'];
            resultJSON += friendArray[index] + ":" + resultArray.length + ",";
            //alert(resultJSON);
        }
    }) (i);
    

    This outer function executes and creates a closure which captures the value of i and uniquely makes it available to the success handler. When it self executes, it returns your success handler which is thus passed to the getJSON function to be called later. But, when it is called later the value of i that you need is available to the success handler via the argument in the self executing function.

    Here's another way to think about closures used with callbacks.

    1. Any function has access to all the variables that are within scope when it's declared, even variables that are up at a higher level in parent scopes and even if the function is called later as a callback. This is actually a huge feature of javascript that many other languages do not have.
    2. So, if we want a variable to be available to a callback function later when the callback executes, we just need to somehow get that variable into the scope of that callback function.

    Here's an example of that:

    function cycleOnOff(sel, cnt, delay) {
        var obj = $(sel);
    
        function next() {
            if (cnt-- > 0) {
                obj.toggle();
                setTimeout(next, delay);
            }
        }
        next();
    }
    

    In this case, the function next() is a callback to setTimeout(), but that function has full access to the variables within its parent scope: sel, cnt, delay and obj.

    1. If the variable doesn't change between the time the callback is initially set and when the callback gets called, then it's pretty easy. You can just use an anonymous function declaration and all higher scope variables available at the time of defining the anonymous function will still be available when the callback is called at some later time.
    2. If the variable does change as code continues to execute and you want to make a specific value that it has now available to the callback when it is later called - this is when it gets a little trickier. What one can do is to create a function that you pass this variable into, thus creating a scope where that variable has the value you want and where it won't change as the other code continues to execute. But, because what we want is a callback function, not just a function call, we have to combine the two in a semi-weird way. We make a function call and pass it the desired value. In that function call, we return a reference to our callback function. This assigns the callback function appropriately, but it puts the callback function into a closure that captures the value of our desired variable. Even better, this closure is unique to this particular instance of the callback so every use of the callback will have it's own closure and thus it's own unique value of that variable. The closure/callback we created for your particular problem is an example of this.
    0 讨论(0)
提交回复
热议问题