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

IT技术 javascript jquery variables scope callback
2021-01-30 05:29:02

这可能更像是一个范围界定问题。我正在尝试在 $.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!!

对我的答案的一些后续评论(我很感激他们)。我这样做的目的是首先加载一个带有问题列表的 JSON 对象,然后用户可以从中删除并保存这些问题。但是,这是通过在页面上后续交互做,我不能预见用户将要使用JSON对象做回调。因此需要在回调完成后使其可访问。有没有人看到我的逻辑有缺陷?说真的,因为可能有一些我没有看到的东西......

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

有谁知道在发生这种情况时我应该如何阻止用户交互?为什么会有这样的担忧?再次感谢所有的答复。

6个回答

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

所以,鉴于此:

a();

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

c();

a, b, and的调用顺序c可能是a b c在本例中想要的)或a c b(更可能实际发生)。

解决方案?

同步 XHR 请求

使请求同步而不是异步:

a();

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

c();

重构代码

将呼叫移动到呼叫cb

a();

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

    c();
});
一个响亮的回答。不幸的是(正如 OP 在问题更新中发现的那样),$.getJSON没有为选项提供“选项覆盖” asynch@Mega Matt:您必须调用$.ajax 而不是 $.getJSON, 传递dataType:"json"才能执行与 getJSON 相同的工作。
2021-03-18 05:29:02
@strager,我的意思并不总是,我的意思是在 JavaScript Ajax 程序中。$document ready 用于设置点击处理程序之类的东西。在 JavaScript 中同步而不是异步是一个坏主意,因为 JS 是单线程的,线程无法结束。界面出现问题,一些浏览器会发出有关脚本未结束的警报。由于学习 Ajax 的目标通常是创建响应式网页或 RIA(不是命令行应用程序),因此需要学习异步。
2021-03-20 05:29:02
oop,我的意思是async,不是asynch想到的另一个选项是通过$.ajaxSettings.async = false. 请注意,这会影响所有 XMLHttpRequest。
2021-03-21 05:29:02
感谢 strager 的快速回复。你必须原谅我......即使有 CS 学位,我仍然对这些东西有点菜鸟。我想我已经看到您可以在 $.ajax(..) 中将 async 设置为 false?我可以说“$.ajax({async: false});”吗?此外,也许更重要的是,异步关闭后意味着什么?一切都从上到下执行?再次感谢..
2021-03-24 05:29:02
没有充分的理由同步而不是异步。只需将代码放入回调中即可。
2021-04-09 05:29:02

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

@Nosredna:IMO,自定义事件未被充分利用。它们非常适合清理内联事件处理程序倾向于产生的嵌套匿名函数意大利面。
2021-03-15 05:29:02
戴夫,我认为您的回答可能违反了我对异步调用的原始问题。全局变量似乎是一个很好的解决方案,但前提是我可以确保在 $.getJSON 运行调用它。如果我需要能够在回调完成后操作数据,听起来我唯一可以将数据存储在回调范围之外的变量中(并且在我需要的范围内)。并且唯一的方法是确保将变量的值设置为将 ajax 设置为同步。好结论?
2021-03-25 05:29:02
感谢戴夫的回答。所以我想由你运行一个场景。比方说,在 $.getJSON 回调中,我获取从调用中获得的数据,并加载一个 jquery 拖放列表,然后用户可以选择从中删除问题。用户不希望分配给他的特定问题,并“删除”它。然后他想保存分配给他的那个列表。在这里我想更新该信息,一个 JSON 对象将是完美的。但我不再能够访问该信息,因为回调已完成执行。我没有要从中删除问题的列表!我该如何处理?
2021-03-31 05:29:02
我从没想过使用自定义事件。我会努力做到这一点。很好的答案。
2021-04-03 05:29:02
@Matt:看看我最近的编辑,包括 OnDrop 和 SaveChanges 函数,看看这是否有意义。对于事件驱动代码,其想法是根据需要对这些事件采取行动,而不是编排某个代码链以同步顺序执行所有事件。当您在单线程浏览器环境中工作时,其他任何事情都会与规则背道而驰;尤其是在使用事件驱动的框架(如 jQuery)时。
2021-04-06 05:29:02

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

$variable= new array();

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

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

console.log($variable);

希望对你有帮助.. :)

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

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

它非常直接,也是一种让异步代码感觉更加必要的可行方法。

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

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

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

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

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

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

我已经在 J​​S 中完成了计算密集型金融算法。即便如此,它也是一样的——你把它分解成小部分,事件是超时。

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

你已经说服我同步 ajax 不是要走的路,但那时我仍然在为 flow 苦苦挣扎。请参阅我对 Dave Ward 回答的后续评论。
2021-03-23 05:29:02