Javascript事件同步
我正在建立一个非常沉重的javascript(使用jQuery)的音乐会日历。 我在整个应用程序中同步各种事件时遇到了问题,我正在寻找有关如何执行此操作的建议。
一个简单用例的例子:
- 用户点击一个月
- 日历会跳到该月
一个更复杂的用例的例子:
- 用户选择一位艺术家
- 日历确定该艺术家的首次演出的日期
- 日历会跳到该月
- 日历突出显示艺术家的节目
一个偶然的问题是,当我试图突出艺术家的节目时,新月还没有呈现。 因此,即使按顺序调用这些函数,也不会突出显示该节目。 显然,使用setTimeout()是非常hacky,并不能保证工作。
首先,一个简单的问题 – 是否有可能(即使在Chrome中)以下函数不按顺序运行?
function steps(){ stepOne(); //TAKES 30 SECONDS stepTwo(); //TAKES < 1 SECOND }
第二,一个相关的简单问题:
如果放在函数的末尾,则JS回调总是会运行 给定函数中的其他所有内容都已运行完毕?
如果是这样,我可以将每个函数嵌套为其先前函数的回调。 但是,一旦考虑了所有不同的用例,这可能会变得难以处理。
这是我正在考虑的方法:
1)允许每个函数成为可选的回调参数。 如果它存在, 在函数的最后调用它。 2)在UI刷新期间,创建一个数组,并堆叠任何函数 在这个数组中调用。 3)完成这个“脚本”后,遍历数组,调用 使用下一个函数按顺序添加每个函数 作为前一个函数的回调。
我想这会确保按顺序调用所有函数。
另一种方法是使用附加事件侦听器
$(document).bind("listener.name", fnCallback);
然后打电话
$(document).trigger("listener.name");
每当事件发生时。
但是,我猜这也有点笨拙,考虑到不同的事件可能需要根据用例调用不同的函数集。 我总是可以打电话
$(document).unbind("listener.name");
在向它添加新事件之前,但是再次 – 我倾向于创建一种主要的“脚本”,正如我在第一种方法中所建议的那样。
希望这不是太模糊 – 任何反馈? 任何必须同步各种事件的复杂UI的经验?
非常感谢,
迈克尔
你的方法#1是最好的方法,而且最自然的是使用jQuery。 大多数作用于用户界面并执行某些操作的函数接受一个回调函数参数,该参数在函数执行后被调用。
如果你正在做的事情没有在jQuery中实现,遵循相同的模式将使你的代码更具可读性。 多米尼克的答案是一个很好的简洁例子:
function steps(){ stepOne(stepTwo); } function stepOne(callback){ var AsyncDone = function() { //any Synchronus Things here callback(); } someAsyncFunction( params, AsyncDone ); }
尝试传入要回调的函数作为参数
function steps(){ stepOne(stepTwo); } function stepOne(callback){ var AsyncDone = function() { //any Synchronus Things here callback(); } someAsyncFunction( params, AsyncDone ); }
在我看来,使用自定义事件的最后一种方法是最好的方法。
设计各种组件和事件,让它们相互交互。
例如,假设你有一个Calendar对象。
var calendar = function() { var pub = {}; pub.highlightRow = function(row) {}; pub.getRowByContent = function(content) { }; pub.selectMonth = function() { //your code to actually select month. //Once all the necessary DOM work is done, fire the //monthSelected event (namespacing the event so as to avoid the clash with other events). $(document).trigger('calendar:monthSelected'); }; return pub; }();
现在你的艺术家搜索方法可能看起来像,
function searchArtist(artistName) { $(document).bind('calendar:monthSelected'), function() { calendar.highlightRow(calendar.getRowByContent(artistName)); } ); calendar.selectMonth(getShowMonthByArtist(artistName)); }