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

时间:2009-11-16 02:49:47

标签: javascript jquery variables scope callback

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

var jsonIssues = {};  // declare json variable

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

// jsonIssues not accessible here

在另一篇文章中提到了类似这样的问题,并且大家一致认为我需要在回调函数中完成我需要做的任何事情,并且无法在其他任何地方访问。我真的没办法在$ .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!!

对我的答案采取后续评论(我非常感谢他们)。我这样做的目的是最初加载一个JSON对象,其中包含用户可以从中删除的问题列表,然后保存。但这是通过页面上的后续交互来完成的,我无法预见用户想要在回调中使用中的JSON对象。因此,一旦回调完成就需要使其可访问。有没有人在我的逻辑中看到一个缺陷?说真的,因为可能有些东西我没看到......

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

有没有人知道在这种情况下我应该如何阻止用户互动?为什么这么关注?再次感谢所有回复。

6 个答案:

答案 0 :(得分:34)

$.getJSON是异步的。也就是说,执行调用后的代码会在$.getJSON获取并解析数据并调用您的回调时执行。

所以,鉴于此:

a();

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

c();

abc的来电顺序可以是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();
});

答案 1 :(得分:9)

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

答案 2 :(得分:5)

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

$variable= new array();

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

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

console.log($variable);

希望它对你有所帮助.. :)

答案 3 :(得分:4)

你可以用承诺来解决这个问题:

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

这是非常直接的,并且使异步代码感觉更加必要的可行方法。

答案 4 :(得分:1)

“但这是通过页面上的后续交互来完成的,我无法预见用户将在回调中使用JSON对象做什么。”

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

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

大多数情况下,您的代码都不会运行。对Ajax页面进行编程就是考虑在什么时候可能发生的事件。

有一个原因是它是“Ajax”而不是“Sjax”。将异步更改为同步是一件很痛苦的事。预计你会把页面异步。

事件驱动的编程起初可能令人沮丧。

我在JS中完成了计算密集型的财务算法。即使这样,它也是一样的 - 你把它分解成一小部分,事件就是超时。

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

答案 5 :(得分:-3)

您正在遇到范围问题。

简答:

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

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

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

答案很长:

Scoping issue in Javascript Javascript closure scoping issue