在第一次 Ajax 调用之后,DOM 不会在依赖于第一个的第二个 ajax 调用之前更新

Posted

技术标签:

【中文标题】在第一次 Ajax 调用之后,DOM 不会在依赖于第一个的第二个 ajax 调用之前更新【英文标题】:After first Ajax call, DOM isn't updating before the second ajax call that's dependent on the first 【发布时间】:2019-01-27 06:38:57 【问题描述】:

我正在创建一个应用程序,允许人们从列表拖动到插槽,然后插槽可以接受其中的几个子项,例如插槽 A-1、A-2、...

所有这些交互都是通过 jQuery UI 的 draggabledroppable 完成的,但最后调用的函数包含一个 Ajax 调用来加载 Slot 及其子项的内容。

请务必注意,所有子项都依赖于 Slot。

据我所知,我已经尝试在 $(document).ready() 上模拟这个输入,并且由于默认情况下 ajax 和函数是异步的,有些执行得更快,有些执行得更慢,有些子项失败,因为此时 Slot 没有更新.

我已尝试通过调用这些函数 async 并等待函数来解决此问题,但现在它根本不起作用,即使调用以正确的顺序进行,这确实令人困惑。

第二个 ajax 调用对第一个调用的依赖性与第一个元素有关,该元素具有第二个调用所需的特定数据属性,并且由于某种原因,它始终未定义,即使在技术上不应该如此。我将在下面的示例中进一步解释:

我使用这种设置(它非常简化,但它应该明白重点):

$(document).ready(function()
    LoadDemo();
    //...
); 

async function LoadDemo()

    await LoadSlots();
    await LoadSubitems();


async function LoadSlots()

    LoadSlot(x,y,z);
    LoadSlot(x,y,z);
    LoadSlot(x,y,z);

async function LoadSubitems()

    LoadSubitem(x,y,z,$(".Slot"))
    LoadSubitem(x,y,z,$(".Slot"))
    LoadSubitem(x,y,z,$(".Slot"))

现在在 LoadSlot ajax 内部调用一个 php 脚本,该脚本生成插入到插槽中的 html。此 HTML 还包含所需的数据属性。为了 100% 确保数据信息也加载到 jQuery 中(因为我听说由于某种原因可能存在一些问题)我手动更新 LoadSlot() 调用中的数据,如下所示:

$(name).data("name",$(name).attr("data-name"));

我已经跟踪调试并且可以确认当它被调用时$(name).attr("data-name"不是 undefined/null 并且具有正确的值,这意味着在此之后,数据也应该,但是直到所有 javascript 完成处理,数据仍未定义。

此外,即使添加子项的函数出现在 Slot 调用之后,一旦出现 ajax 错误警报,DOM 仍然不包含它应该在那个点上的 HTML,就像它被卡住,直到所有代码都被处理,即使它不应该是。

一旦初始 javascript 结束并关闭所有警报,我就可以从列表中进行拖放(同样,它会做同样的事情,调用 LoadSlot()LoadSubitem() 并且它工作得很好。

所以问题基本上是这样的: 如何确保在调用 LoadSubitems() 之前使用来自 LoadSlots() 的信息正确更新 DOM?

【问题讨论】:

x y z 是什么,为什么用相同的参数调用LoadSlot()LoadSubItem() 3 次? 你没有显示依赖于数据属性的代码,但我敢打赌你不会等待异步更新。 @Barmar,我已经简化了调用,x、y 和 z,而不是随机参数,但从你的角度来看,我是输入 LoadSlot(".SlotPrimary" ,"item", 1, 1); 还是 LoadSlot(x ,y, z); 并不重要。另一方面,Subitem 调用类似于:LoadSubitem(".SlotPrimary", $(".SlotPrimary .Info"), $(itemlist).find('*[data-name="sub-item-name"]')); 这里从第二个参数 (.Info) 使用 url 调用 ajax:/subitem.php?SlotId="+$(Info).data('slotid')+"&SubItemid="+$(newSubitem).data('subitemid')+"&callback=? 并且 SubItemId 未定义 【参考方案1】:

问题是您没有在LoadSlots() 中使用await(),因此它没有等待AJAX​​ 调用完成。

async function LoadSlots()

    await LoadSlot(x,y,z);
    await LoadSlot(x,y,z);
    await LoadSlot(x,y,z);

当然,这意味着您必须将LoadSlot() 编码为适当的异步函数。如果它调用$.ajax(),你可以简单地让它返回那个调用,因为它返回一个promise。

如果您不希望每个LoadSlot() 调用都等待前一个调用完成,您可以使用Promise.all()

async function LoadSlots() 
    await Promise.all([LoadSlot(x, y, z), LoadSlot(x, y, z), LoadSlot(x, y, z)]);

【讨论】:

我试过这个,不幸的是结果是一样的。我试图用断点进一步调试代码,但我注意到了一个奇怪的现象。使用 promise.all 方法我调用 LoadSlot 5 次和 5 次断点被命中。然后它在 LoadSubitem 中命中 Ajax 调用的断点,只有在这些完成之后,它才会命中 LoadSlot ajax 调用的成功函数。我认为 promise.all 将确保 ajax 及其成功在代码继续到子项之前通过,但我想它没有。你知道为什么吗? 我通过简单地使依赖的 ajax 调用同步来修复它。 不要那样做。 LoadSlot() 是否像我说的那样以 return $.ajax(...); 结尾? 对不起,我一定是错过了那条线。不,它没有。实际的 Load** 函数有额外的检查,并且 ajax 调用是有条件的。

以上是关于在第一次 Ajax 调用之后,DOM 不会在依赖于第一个的第二个 ajax 调用之前更新的主要内容,如果未能解决你的问题,请参考以下文章

在我无法控制的任何 AJAX 调用之后使用 JQuery 修改 DOM

vue nextTick使用

在AJAX调用之后,我的数据表不会刷新

在 ajax 发布之后,附加的 div 不在 IE 8 中显示

react生命周期详解

React生命周期