web-dev-qa-db-fra.com

Les variables définies pendant la fonction $ .getJSON ne sont accessibles que dans la fonction

Cela peut être plus une question de portée. J'essaie de définir un objet JSON dans une fonction $ .getJSON, mais je dois pouvoir utiliser cet objet en dehors du rappel.

var jsonIssues = {};  // declare json variable

$.getJSON("url", function(data) {
    jsonIssues = data.Issues;
});

// jsonIssues not accessible here

Une question similaire à celle-ci a été posée dans un autre article, et le consensus était que tout ce que je dois faire avec les objets JSON doit être fait dans la fonction de rappel et ne peut être consulté nulle part ailleurs. N'y a-t-il vraiment aucun moyen de continuer à accéder/manipuler cet objet JSON en dehors du rappel $ .getJSON? Qu'en est-il du retour de la variable ou de la définition d'un global?

J'apprécierais toute aide. Cela ne semble pas juste ...

MISE À JOUR:

J'ai essayé de définir le paramètre asynchrone $ .ajax () sur false et d'exécuter le même code, sans succès. Le code que j'ai essayé est ci-dessous:

var jsonIssues = {};  // declare json variable

$.ajax({ async: false });

$.getJSON("url", function(data) {
    jsonIssues = data.Issues;
});

// jsonIssues still not accessible here

En outre, j'ai eu quelques réponses selon lesquelles une variable globale devrait fonctionner correctement. Je dois préciser que tout ce code se trouve dans $(document).ready(function() {. Pour définir une variable globale, dois-je simplement la déclarer avant le document.ready? En tant que tel:

var jsonIssues = {};

$(document).ready(function() {

  var jsonIssues = {};  // declare json variable

  $.getJSON("url", function(data) {
      jsonIssues = data.Issues;
  });

  // now accessible?
}

J'avais l'impression qu'une variable déclarée dans document.ready devrait être accessible "globalement" et modifiable dans n'importe quelle partie de document.ready, y compris des sous-fonctions comme la fonction de rappel $ .getJSON. J'ai peut-être besoin de lire sur la portée des variables javascript, mais il ne semble pas être facile de réaliser ce que je veux. Merci pour toutes les réponses.

MISE À JOUR # 2: Par les commentaires donnés aux réponses ci-dessous, j'ai utilisé $ .ajax au lieu de .getJSON, et j'ai atteint le les résultats que je voulais. Le code est ci-dessous:

var jsonIssues = {};
    $.ajax({
        url: "url",
        async: false,
        dataType: 'json',
        success: function(data) {
            jsonIssues = data.Issues;
        }
    });

    // jsonIssues accessible here -- good!!

Quelques commentaires de suivi sur mes réponses (et je les apprécie tous). Mon objectif en faisant cela est de charger un objet JSON initialement avec une liste de problèmes que l'utilisateur peut ensuite supprimer et enregistrer. Mais cela se fait via des interactions ultérieures sur la page, et je ne peux pas prévoir ce que l'utilisateur voudra faire avec l'objet JSON dans le rappel. D'où la nécessité de le rendre accessible une fois le rappel terminé. Quelqu'un voit-il un défaut dans ma logique ici? Sérieusement, car il y a peut-être quelque chose que je ne vois pas ...

En outre, je lisais la documentation jQuery .ajax (), et il est dit que définir async sur false "Charge les données de manière synchrone. Bloque le navigateur pendant que les demandes sont actives. Il est préférable de bloquer l'interaction de l'utilisateur par d'autres moyens lorsque la synchronisation est nécessaire . "

Quelqu'un a-t-il une idée de la façon dont je dois bloquer l'interaction des utilisateurs pendant que cela se passe? Pourquoi est-ce une telle préoccupation? Merci encore pour toutes les réponses.

43
MegaMatt

$.getJSON est asynchrone. Autrement dit, le code après l'appel est exécuté pendant que $.getJSON récupère et analyse les données et appelle votre rappel.

Donc, étant donné cela:

a();

$.getJSON("url", function() {
    b();
});

c();

L'ordre des appels de a, b et c peut être soit a b c (ce que vous voulez, dans ce cas) ou a c b (plus susceptible de se produire).

La solution?

Demandes XHR synchrones

Rendez la demande synchrone au lieu d’asynchrone:

a();

$.ajax({
    async: false,
    url: "url",
    success: function() {
        b();
    }
});

c();

Code de restructuration

Déplacez l'appel vers c après l'appel à b:

a();

$.getJSON("url", function() {
    b();

    c();
});
34
strager

N'oubliez pas que lorsque vous fournissez une fonction de rappel, le but de cela est de reporter l'exécution de ce rappel à plus tard et de poursuivre immédiatement l'exécution de la suite. Cela est nécessaire en raison du modèle d'exécution à thread unique de JavaScript dans le navigateur. Forcer l'exécution synchrone est possible, mais il bloque le navigateur pendant toute la durée de l'opération. Dans le cas de quelque chose comme $ .getJSON, il s'agit d'un temps prohibitif pour que le navigateur cesse de répondre.

En d'autres termes, vous essayez de trouver un moyen d'utiliser ce paradigme procédural:

var foo = {};

$.getJSON("url", function(data) {
  foo = data.property;
});

// Use foo here.

Lorsque vous devez refactoriser votre code afin qu'il se déroule davantage comme ceci:

$.getJSON("url", function(data) {
  // Do something with data.property here.
});

"Faire quelque chose" pourrait être un appel à une autre fonction si vous voulez garder la fonction de rappel simple. La partie importante est que vous attendez la fin de $ .getJSON avant d'exécuter le code.

Vous pouvez même utiliser des événements personnalisés pour que le code que vous avez placé après $ .getJSON s'abonne à un événement IssuesReceived et que vous déclenchiez cet événement dans le rappel $ .getJSON:

$(document).ready(function() {
  $(document).bind('IssuesReceived', IssuesReceived)

  $.getJSON("url", function(data) {
    $(document).trigger('IssuesReceived', data);
  });
});

function IssuesReceived(evt, data) {
  // Do something with data here.
}

Mise à jour:

Ou, vous pouvez stocker les données globalement et simplement utiliser l'événement personnalisé pour notifier que les données ont été reçues et la variable globale mise à jour.

$(document).ready(function() {
  $(document).bind('IssuesReceived', IssuesReceived)

  $.getJSON("url", function(data) {
    // I prefer the window.data syntax so that it's obvious
    //  that the variable is global.
    window.data = data;

    $(document).trigger('IssuesReceived');
  });
});

function IssuesReceived(evt) {
  // Do something with window.data here.
  //  (e.g. create the drag 'n drop interface)
}

// Wired up as the "drop" callback handler on 
//  your drag 'n drop UI.
function OnDrop(evt) {
  // Modify window.data accordingly.
}

// Maybe wired up as the click handler for a
//  "Save changes" button.
function SaveChanges() {
  $.post("SaveUrl", window.data);
}

Mise à jour 2:

En réponse à cela:

Quelqu'un a-t-il une idée de la façon dont je dois bloquer l'interaction des utilisateurs pendant que cela se passe? Pourquoi est-ce une telle préoccupation? Merci encore pour toutes les réponses.

La raison pour laquelle vous devriez éviter de bloquer le navigateur avec des appels synchrones AJAX est que n thread JavaScript bloqué bloque également tout le reste du navigateur, y compris d'autres onglets et même d'autres fenêtres . Cela signifie pas de défilement, pas de navigation, rien. À toutes fins utiles, il semble que le navigateur soit tombé en panne. Comme vous pouvez l'imaginer, une page qui se comporte de cette façon est un significatif nuisance pour ses utilisateurs.

9
Dave Ward

peut-être que ce travail fonctionne pour moi .. :)

$variable= new array();

$.getJSON("url", function(data){
asignVariable(data);
}

function asignVariable(data){
$variable = data;
}

console.log($variable);

J'espère que cela vous aidera .. :)

5
Alexander

Vous pourriez aborder cela avec des promesses:

var jsonPromise = $.getJSON("url")

jsonPromise.done(function(data) {
    // success
    // do stuff with data
});

jsonPromise.fail(function(reason) {
    // it failed... handle it
});

// other stuff ....

jsonPromise.then(function(data) {
    // do moar stuff with data
    // will perhaps fire instantly, since the deferred may already be resolved.
});

C'est assez simple et un moyen viable de rendre le code asynchrone plus impératif.

4
Björn Roberg

"Mais cela se fait via des interactions ultérieures sur la page, et je ne peux pas prévoir ce que l'utilisateur voudra faire avec l'objet JSON dans le rappel."

Le rappel est l'occasion de configurer l'écran pour l'interaction de l'utilisateur avec les données.

Vous pouvez créer ou révéler du code HTML pour l'utilisateur et configurer davantage de rappels.

La plupart du temps, aucun de votre code ne s'exécutera. La programmation d'une page Ajax consiste à penser aux événements qui peuvent se produire quand.

Il y a une raison pour laquelle c'est "Ajax" et non "Sjax". Il y a une raison pour laquelle il est difficile de passer de l'asynchrone à la synchronisation. Il est prévu que vous fassiez la page en mode asynchrone.

La programmation événementielle peut être frustrante au début.

J'ai fait des algorithmes financiers intensifs en calcul dans JS. Même alors, c'est la même chose - vous le divisez en petites parties, et les événements sont des délais d'attente.

L'animation en JavaScript est également pilotée par les événements. En fait, le navigateur n'affichera même pas le mouvement à moins que votre script n'abandonne le contrôle à plusieurs reprises.

1
Nosredna