在第一次 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 的 draggable
和 droppable
完成的,但最后调用的函数包含一个 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