javascript-$ .getJSON函数期间设置的变量只能在函数内访问

这可能是一个范围更广的问题。 我正在尝试在$ .getJSON函数中设置一个JSON对象,但我需要能够在回调之外使用该对象。

var jsonIssues = {};  // declare json variable

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

// jsonIssues not accessible here

在另一篇文章中也提出了类似的问题,共识是我需要对JSON对象做的任何事情都必须在回调函数中完成,而不能在其他任何地方访问。 真的没有办法继续在$ .getJSON回调之外继续访问/操作该JSON对象吗? 返回变量或设置全局变量怎么办?

我将不胜感激。 这似乎不正确...

更新:

尝试将$ .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() {之内。要设置全局变量,我是否应该在document.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!!

将后续评论添加到我的回答中(我非常感谢)。 我这样做的目的是首先用一个Issues列表加载JSON对象,然后用户可以从中删除并保存。 但这是通过页面上的后续交互完成的,而且我无法预见用户将要对回调中的JSON对象执行的操作。 因此,需要在回调完成后使其可访问。 有人在这里看到我的逻辑缺陷吗? 严重的是,因为可能有些东西我没看到...

另外,我阅读了.ajax()jQuery文档,并说将async设置为false“将同步加载数据。在请求处于活动状态时阻止浏览器。最好在需要同步时通过其他方式阻止用户交互 ”。

有谁知道在这种情况下我应该如何阻止用户交互? 为什么这么担心? 再次感谢您的所有答复。

MegaMatt asked 2020-08-06T06:11:44Z
6个解决方案
34 votes

c是异步的。 也就是说,在b提取并解析数据并调用回调时,将执行调用后的代码。

因此,鉴于此:

a();

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

c();

cbc的呼叫顺序可以是a b c(在这种情况下是您想要的)或a c b(实际发生的可能性更高)。

解决方案?

同步XHR请求

使请求同步而不是异步:

a();

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

c();

重组代码

将呼叫移至b之后将呼叫移至c

a();

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

    c();
});
strager answered 2020-08-06T06:12:21Z
9 votes

请记住,提供回调函数时,关键是将该回调的执行推迟到以后再立即继续执行下一步。 这是必需的,因为浏览器中的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线程也会阻塞浏览器中的所有其他内容,包括其他选项卡,甚至其他窗口。 那意味着没有滚动,没有导航,什么也没有。 出于所有意图和目的,似乎浏览器已崩溃。 您可以想象,以这种方式运行的页面对其用户来说是一个很大的麻烦。

Dave Ward answered 2020-08-06T06:13:27Z
5 votes

也许这项工作对我有用.. :)

$variable= new array();

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

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

console.log($variable);

希望对您有帮助。:)

Alexander answered 2020-08-06T06:13:51Z
4 votes

您可以通过承诺来实现这一目标:

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

这是非常简单明了的方法,也是使异步代码更具必要性的可行方法。

Björn Roberg answered 2020-08-06T06:14:16Z
1 votes

“但是,这是通过页面上的后续交互完成的,我无法预见用户将要对回调中的JSON对象执行的操作。”

回调是您为用户与数据交互设置屏幕的机会。

您可以为用户创建或显示HTML,并设置更多回调。

大多数情况下,您的代码都不会运行。 对Ajax页面进行编程仅是考虑何时可能发生哪些事件。

有一个原因是“ Ajax”而不是“ Sjax”。 从异步更改为同步是一个痛苦的原因。 预计您将执行页面异步操作。

首先,事件驱动的编程可能令人沮丧。

我已经在JS中完成了计算密集型财务算法。 即便如此,这也是同一件事-您将其分解成小部分,事件就是超时。

JavaScript中的动画也是事件驱动的。 实际上,除非您的脚本反复放弃控制,否则浏览器甚至不会显示移动。

Nosredna answered 2020-08-06T06:15:07Z
-3 votes

您只是遇到范围问题。

简短答案:

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封闭作用域问题

johnvey answered 2020-08-06T06:15:41Z
translate from https://stackoverflow.com:/questions/1739800/variables-set-during-getjson-function-only-accessible-within-function