小编典典

异步请求后数组中的未定义索引

ajax

我在一个数组上遇到了一些困难,该数组(在异步调用之外)定义得很好,但是当我在一个异步请求(例如$
.getJSON)中调用其索引时,该数组的所有索引都未定义,但是 长度 是还是一样。这是我的代码。

我指的数组是 friendsArray

该数组在第二个“ $
.getJSON”调用期间具有正确的索引,但是在该函数的回调内部,其所有索引都变为未定义。由于数组是在方法范围内定义的,因此不应该保留其值吗?

if (response.status === 'connected') { 
var accessToken = $.trim(response.authResponse.accessToken);
var hashArray = [];
var friendArray = [];
document.getElementById("statusCheck").innerHTML = accessToken;
$.getJSON('https://graph.facebook.com/me/friends?access_token=' + accessToken, 
  function(dataJSON){
    hashArray = dataJSON['data'];
    for (var i = 0; i < hashArray.length; i++){
        friendArray.push(hashArray[i]["id"]);
    }
    var resultJSON = "{";
    var resultArray = [];

    for (var i = 0; i < friendArray.length; i++){
        $.getJSON('https://graph.facebook.com/me/mutualfriends/' + 
                  friendArray[i] + "?access_token=" + accessToken, 
            function(dataJSON2){
                resultArray = dataJSON2['data'];
                resultJSON += friendArray[i] + ":" + resultArray.length + ",";
                //alert(resultJSON);
            })
        if (i == friendArray.length - 1){
            postArrayPopulation(resultJSON);
        }
    }

});

}


阅读 367

收藏
2020-07-26

共1个答案

小编典典

问题在于,ajax函数完成后,回调函数会在一段时间后发生。届时,数组索引将前进到for循环的末尾(因此它指向数组的末尾)为未定义的值。该数组仍然存在,但是在调用完成函数时,索引已更改。

通常,将索引获取到成功处理程序中的技术是在函数闭包中捕获该索引,在该闭包中捕获该索引以供完成函数使用。

您可以使用以下内容替换成功处理程序,从而创建一个捕获索引值的闭包:

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

该外部函数执行并创建一个闭包,该闭包捕获i的值,并使它唯一可用于成功处理程序。当自身执行时,它将返回成功处理程序,该处理程序随后将传递给getJSON函数,以供稍后调用。但是,稍后调用它时,所需的值i可通过自执行函数中的参数提供给成功处理程序。

这是考虑与回调一起使用的闭包的另一种方法。

  1. 任何函数在声明时都可以访问作用域内的所有变量,即使在父作用域中处于较高级别的变量也可以访问,即使该函数后来被称为回调。这实际上是许多其他语言所没有的javascript的巨大功能。
  2. 因此,如果我们希望变量在以后执行回调时可供回调函数使用,我们只需要以某种方式使该变量进入该回调函数的范围即可。

这是一个例子:

function cycleOnOff(sel, cnt, delay) {
    var obj = $(sel);

    function next() {
        if (cnt-- > 0) {
            obj.toggle();
            setTimeout(next, delay);
        }
    }
    next();
}

在这种情况下,该功能next()是一个回调setTimeout(),但该功能已完全进入到其父范围内的变量:selcntdelayobj

  1. 如果变量在初始设置回调和调用回调之间没有变化,则非常简单。您可以只使用匿名函数声明,并且在稍后调用回调时,在定义匿名函数时可用的所有更高范围的变量仍将可用。
  2. 如果变量确实随着代码继续执行而发生更改,并且您想提供一个特定的值,则该变量现在在以后被调用时可供回调使用-这是在棘手的情况下。一个人所能做的就是创建一个函数,将这个变量传递给它,从而创建一个范围,使该变量具有所需的值,并且在该范围内不会随着其他代码的继续执行而改变。但是,因为我们要的是回调函数,而不仅仅是函数调用,所以我们必须以半古怪的方式将两者结合起来。我们进行函数调用并将其传递给所需的值。在该函数调用中,我们返回对回调函数的引用。这会适当地分配回调函数,但是会将回调函数放入一个捕获所需变量值的闭包中。更好的是 这个闭包对于该回调的特定实例是唯一的,因此对回调的每次使用都将拥有它自己的闭包,因此它是该变量的唯一值。我们为您的特定问题创建的关闭/回调就是一个例子。
2020-07-26