1

我正在开发一个使用 jQuery 的 web 应用程序,并且在测试它时我得到的东西看起来可能是一种竞争条件。尽管我尽了最大的努力,但我不确定如何进行。

代码在GitHub 上,但我将在这里总结奇怪的行为。

早期的 AJAX 请求

我有一些代码需要 AJAX 调用和准备好 DOM。为了加快速度,我在 $(document).ready() 事件触发之前进行了 AJAX 调用。在链接的 JS 文件中,这是“init”函数。此函数调用 _build_site_select,它设置 AJAX 请求。完成后,调用 _on_site_list_success。

在 $(document).ready()

当我到达 ready() 时,我会进行需要触发 AJAX 和 ready() 事件的调用。在链接的代码中,这是 populate_site_select 调用。由于调用 ready() 时 AJAX 可能未完成,因此我检查了在 AJAX 操作完成后设置的变量,如果还为时过早无法完成,则使用 setTimeout 延迟对 populate_site_select 的调用。变量 site_list_ready 在 AJAX 调用完成时设置,并在需要站点列表在执行之前完全完成的函数中进行检查。

预期和观察到的行为

我希望看到的行为是 populate_site_select 只有在 _on_site_list_select 中的对象/关联数组完全填充后才会被调用。然而,这并非总是如此。有时,当我到达 populate_site_select 时,该数组只是部分填充 - 它似乎与失败的方式一致(它始终是数组中的同一个条目,而不是我期望的 ~30 左右)。

我试过的

我还尝试将 setTimeout 调用添加到 _on_site_list_success 调用,这进一步将数组的填充与 site_list_ready 变量的设置分开。但是,这并不能避免问题。

我知道从 AJAX 调用返回的 JSON 数据是正确的(我可以在 chrome 调试器中查看它),如果我稍后检查站点列表变量的值,(在页面完成加载后)它会正确填充。

这似乎不是什么不寻常的场景,我很难相信这个错误是在 Chrome 中(尽管我没有用其他浏览器测试过这个)。我究竟做错了什么?

4

1 回答 1

2

我没有尝试下面的代码,但是 jQuery 的Deferred对象可以帮助你。

var domReady, ajax;
domReady = jQuery.Deferred();

jQuery(function () {
    // on DOM ready
    domReady.resolve();
});

ajax = jQuery.ajax({
  url: '/path/to/file',
  type: 'GET',
  dataType: 'xml/html/script/json/jsonp'
});

jQuery.when(domready, ajax).then(doneCallbacks, failCallbacks);

基本上,您有两个延迟对象,一个处理 DOM 就绪状态,另一个处理 AJAX 调用;我们手动管理第一个对象,在 DOM 准备好时解析它;第二个由 jQuery 本身自动管理($.ajax对象是Deferred对象,并且在 AJAX 调用成功时被解析)。

最后,jQuery.when()我们观察延迟对象的状态,当它们都解决时,doneCallback触发;如果两个对象之一被拒绝,failCallback则被解雇。

所以,doneCallbacks是两个 Deferred 对象解析后将调用的函数,这样 DOM 就准备好了,并且 AJAX 调用已经完成并成功。

请参阅对象的文档jQuery.when()Deferred

于 2012-04-28T14:53:38.483 回答