我有一个棘手的问题,可以通过链式回调解决,但这导致相当复杂的代码。
我有一些嵌套组件:jQueryUI对话框。在其中,我有jQueryUI选项卡。在每个选项卡中,我有一个DataTables组件,调用AJAX数据。
我的问题是,当我在对话框中加载所有HTML时,所有内容都会并行启动:标签尝试创建自己,而每个DataTable同时收集它的数据!
结果是完全混乱:Tabs不包含正确的元素,因为每个DataTable在Tabs初始化之后在DOM上创建新节点。 Dialog采用了错误的维度,因为DOM在初始化时很小,但在每个DataTable显示数据时都会长大。
为了使事情有效,我需要:
1) Wait for each DataTable to initialize.
2) When they're all done, initialize the Tabs.
3) When Tabs are ready, finally open the Dialog.
有一种简单的方法吗?我目前正在使用大量的回调,并且所有内容都是动态的,数据库驱动的,所以我必须进行大量的泛化,几乎没有什么可以硬编码。事情已经奏效,但它很难看!
如果可以的话,这是我会关闭JavaScript异步行为并使其全部同步和顺序的情况之一。
也许jQuery队列,承诺或类似的东西可以帮助我?任何帮助将不胜感激!
答案 0 :(得分:1)
我找到了合适的解决方案,因此我会在此发布,以帮助其他遇到类似问题的人。
首先,我发现DataTables在创建时触发了一个事件。这是“init”事件:
$("#TableID").on("init", function() { whatever(); } );
其次,我的另一个问题是在初始化选项卡之前我必须等待的不确定数量的DataTable。所以我创建了一个名为RenderManager的小函数来跟踪我的所有DataTable。当最后一个完成时,将调用回调。我使这个功能非常通用,所以它可以用在任何需要等待几个并行处理才能完成的情况下:
function RenderManager(action, id, callback)
{
if(typeof RenderManager.groups == 'undefined' ) RenderManager.groups = {};
switch(action)
{
case "init":
RenderManager.groups[id] = { _callback:callback, _counter:0 };
break;
case "add":
if(typeof RenderManager.groups[id] == 'undefined' )
console.log('Group "'+id+'" referenced before init.');
else
RenderManager.groups[id]._counter++;
break;
case "remove":
if(typeof RenderManager.groups[id] == 'undefined' )
console.log('Group "'+id+'" referenced before init.');
else
{
RenderManager.groups[id]._counter--;
if(RenderManager.groups[id]._counter == 0)
RenderManager.groups[id]._callback();
}
break;
}
}
用法很简单:首先,使用init调用它,以通知组名称和所需的回调:
RenderManager('init', 'MyGroup', function() { CreateTabs(); });
对于创建的每个DataTable(或并行proccess),将其添加到组中:
RenderManager('add', 'MyGroup');
然后将remove
绑定到每个DataTable的init
事件(或任何并行进程的完成),使用:
$("#TableID").on("init", function() { RenderManager('remove', 'MyGroup'); } );
就是这样!当最后一个DataTable完成它的工作时,无论执行顺序如何,都将调用CreateTabs();
,无论哪个DataTable首先完成。
正如您所看到的,此函数只是一个计数器:当“堆栈”返回到零时,回调将触发。它可以通过注册每个元素的ID来改进,但这对我目前正在解决的问题来说是过度的。