Tengo algunas dificultades con una matriz que está (fuera de una llamada asíncrona) perfectamente bien definida, pero cuando invoco sus índices dentro de una solicitud asíncrona (por ejemplo, $ .getJSON) todos los índices de la matriz no están definidos pero la longitud es Siempre lo mismo. Aquí está mi código.
La matriz a la que me refiero es friendsArray.
La matriz tiene el índice correcto durante la segunda llamada “$ .getJSON” pero dentro de la callback de esa función, todos sus índices se vuelven indefinidos. ¿No debería la matriz mantener sus valores desde que se definió dentro del scope del método?
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); } } });
}
El problema es que la función de callback ocurre algún tiempo después cuando la función ajax se completa. Para entonces, el índice de la matriz ha avanzado al final de su bucle for
(por lo tanto, apunta al final de la matriz) a un valor indefinido. La matriz aún está allí, pero su índice ha sido cambiado cuando se llama a la función de finalización.
La técnica que normalmente se usa para obtener el índice en el controlador de éxito es capturarlo en un cierre de función donde se captura para usarlo en la función de finalización.
Puede crear un cierre que capture el valor del índice reemplazando su controlador de éxito con esto:
(function(index) { return function(dataJSON2) { resultArray = dataJSON2['data']; resultJSON += friendArray[index] + ":" + resultArray.length + ","; //alert(resultJSON); } }) (i);
Esta función externa se ejecuta y crea un cierre que captura el valor de i y lo hace único para el controlador de éxito. Cuando se ejecuta automáticamente, devuelve el controlador de éxito que, por lo tanto, se pasa a la función getJSON para que se llame más tarde. Pero, cuando se llama más tarde, el valor de i
que necesita está disponible para el controlador de éxito a través del argumento en la función de auto ejecución.
Aquí hay otra forma de pensar acerca de los cierres utilizados con devoluciones de llamada.
Aquí hay un ejemplo de eso:
function cycleOnOff(sel, cnt, delay) { var obj = $(sel); function next() { if (cnt-- > 0) { obj.toggle(); setTimeout(next, delay); } } next(); }
En este caso, la función next()
es una callback a setTimeout()
, pero esa función tiene acceso completo a las variables dentro de su ámbito principal: sel
, cnt
, delay
y obj
.