Переменные, установленные во время функции $ .getJSON, доступны только внутри функции - PullRequest
43 голосов
/ 16 ноября 2009

Это может быть больше из общего вопроса. Я пытаюсь установить объект JSON внутри функции $ .getJSON, но мне нужно иметь возможность использовать этот объект вне функции обратного вызова.

var jsonIssues = {};  // declare json variable

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

// jsonIssues not accessible here

Подобный вопрос, подобный этому, был задан в другом посте, и все согласились с тем, что все, что мне нужно сделать с объектами JSON, должно быть сделано в функции обратного вызова, и к нему нельзя получить доступ где-либо еще. Неужели я не могу продолжать получать доступ / манипулировать этим объектом JSON за пределами обратного вызова $ .getJSON? Как насчет возврата переменной или установки глобальной переменной?

Буду признателен за любую помощь. Это просто кажется неправильным ...

UPDATE:

Попытался установить для асинхронного значения $ .ajax () значение false и выполнить тот же код, но безуспешно. Код, который я попробовал ниже:

var jsonIssues = {};  // declare json variable

$.ajax({ async: false });

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

// jsonIssues still not accessible here

Кроме того, я получил пару ответов о том, что глобальная переменная должна работать нормально. Я должен уточнить, что весь этот код находится в пределах $(document).ready(function() {. Чтобы установить глобальную переменную, я должен объявить ее перед документом .ready? Как таковой:

var jsonIssues = {};

$(document).ready(function() {

  var jsonIssues = {};  // declare json variable

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

  // now accessible?
}

У меня сложилось впечатление, что переменная, объявленная в document.ready, должна быть «глобально» доступной и изменяемой в любой части document.ready, включая подфункции, такие как функция обратного вызова $ .getJSON. Возможно, мне нужно прочитать о области видимости переменных javascript, но, похоже, не так легко добиться того, к чему я стремлюсь. Спасибо за все ответы.

ОБНОВЛЕНИЕ № 2: В комментариях к ответам ниже я использовал $ .ajax вместо .getJSON и добился желаемых результатов. Код ниже:

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

    // jsonIssues accessible here -- good!!

Пара последующих комментариев к моим ответам (и я ценю их все). Моя цель в этом состоит в том, чтобы сначала загрузить объект JSON со списком проблем, которые пользователь затем может удалить и сохранить. Но это делается с помощью последующих взаимодействий на странице, и я не могу предвидеть, что пользователь захочет сделать с объектом JSON в обратном вызове. Отсюда необходимость сделать его доступным после завершения обратного вызова. Кто-нибудь видит недостаток в моей логике здесь? Серьезно, потому что может быть что-то, чего я не вижу ...

Кроме того, я читал документацию по .ajax () jQuery, в которой говорится, что установка async в значение false "Загружает данные синхронно. Блокирует браузер, когда запросы активны. Лучше блокировать взаимодействие с пользователем другими способами, когда необходима синхронизация. "

У кого-нибудь есть идея, как я должен блокировать взаимодействие с пользователем, пока это происходит? Почему это так беспокоит? Еще раз спасибо за все ответы.

Ответы [ 6 ]

34 голосов
/ 16 ноября 2009

$.getJSON является асинхронным. То есть код после вызова выполняется, пока $.getJSON выбирает и анализирует данные и вызывает ваш обратный вызов.

Итак, учитывая это:

a();

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

c();

Порядок вызовов a, b и c может быть либо a b c (что вы хотите в этом случае), либо a c b (с большей вероятностью на самом деле бывает).

Решение?

Синхронные запросы XHR

Сделать запрос синхронным, а не асинхронным:

a();

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

c();

Код реструктуризации

Переместить вызов на c после вызова на b:

a();

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

    c();
});
9 голосов
/ 16 ноября 2009

Помните, что когда вы предоставляете функцию обратного вызова, смысл этого заключается в том, чтобы отложить выполнение этого обратного вызова до более позднего периода и немедленно продолжить выполнение того, что будет дальше. Это необходимо из-за однопоточной модели выполнения JavaScript в браузере. Принудительное синхронное выполнение возможно, но оно зависает браузером на всю продолжительность операции. В случае чего-то вроде $ .getJSON, браузер перестает отвечать на запросы слишком долго.

Другими словами, вы пытаетесь найти способ использовать эту процедурную парадигму:

var foo = {};

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

// Use foo here.

Когда вам нужно реорганизовать ваш код, чтобы он выглядел примерно так:

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

«Делать что-то» может быть вызовом другой функции, если вы хотите сохранить функцию обратного вызова простой. Важной частью является то, что вы ждете, пока $ .getJSON завершит работу, прежде чем выполнять код.

Вы даже можете использовать пользовательские события, чтобы код, который вы поместили после $ .getJSON, подписывался на событие IssuesReceived, и вы вызывали это событие в обратном вызове $ .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.
}

Обновление:

Или вы можете хранить данные глобально и просто использовать пользовательское событие для уведомления о том, что данные были получены и глобальная переменная обновлена.

$(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);
}

Обновление 2:

В ответ на это:

У кого-нибудь есть идея, как я должен блокировать взаимодействие с пользователем, пока это происходит? Почему это так беспокоит? Еще раз спасибо за все ответы.

Причина, по которой вам следует избегать блокировки браузера синхронными вызовами AJAX, заключается в том, что заблокированный поток JavaScript также блокирует все остальное в браузере , включая другие вкладки и даже другие окна. Это означает, что нет прокрутки, нет навигации, нет ничего. В любом случае, кажется, что браузер потерпел крах. Как вы можете себе представить, страница, которая ведет себя таким образом, является существенным неудобством для ее пользователей.

5 голосов
/ 01 февраля 2012

может быть, эта работа, работает для меня ..:)

$variable= new array();

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

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

console.log($variable);

Надеюсь, это поможет вам .. :)

4 голосов
/ 27 августа 2013

Вы можете подойти к этому с обещаниями:

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.
});

Это довольно простой и эффективный способ сделать асинхронный код более императивным.

1 голос
/ 16 ноября 2009

"Но это делается с помощью последующих взаимодействий на странице, и я не могу предвидеть, что пользователь захочет сделать с объектом JSON в обратном вызове."

Обратный вызов - это ваша возможность настроить экран для взаимодействия пользователя с данными.

Вы можете создавать или открывать HTML для пользователя, а также настраивать дополнительные функции обратного вызова.

В большинстве случаев ваш код не будет запущен. Программирование страницы Ajax - все о том, чтобы подумать о том, какие события могут произойти, когда.

Есть причина, по которой это "Аякс", а не "Сякс". Есть причина, по которой трудно переходить с асинхронной синхронизации на другую. Ожидается, что вы сделаете страницу асинхронной.

Программирование на основе событий может поначалу разочаровывать.

Я занимался вычислительными финансовыми алгоритмами в JS. Даже тогда это одно и то же - вы разбиваете его на маленькие части, и события являются таймаутами.

Анимация в JavaScript также управляется событиями. На самом деле, браузер даже не покажет движение, если ваш скрипт повторно не откажется от управления.

0 голосов
/ 16 ноября 2009

Вы просто сталкиваетесь с проблемами определения объема.

Краткий ответ:

window.jsonIssues = {};  // or tack on to some other accessible var

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

// see results here
alert(window.jsonIssues);

Длинные ответы:

Проблема определения объема в Javascript Вопрос определения объема закрытия Javascript

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...