我正在使用jQuery制作类似于The Huffington Post的“From the AP”的自动收报机。股票代码通过用户命令(单击箭头)或自动滚动来旋转ul。
默认情况下,每个列表项都显示为:none。通过添加“showHeadline”类来显示它是display:list-item。 UL的HTML看起来像这样:
<ul class="news" id="news">
<li class="tickerTitle showHeadline">Test Entry</li>
<li class="tickerTitle">Test Entry2</li>
<li class="tickerTitle">Test Entry3</li>
</ul>
当用户单击右箭头或自动滚动setTimeout关闭时,它会运行tickForward()函数:
function tickForward(){
var $active = $('#news li.showHeadline');
var $next = $active.next();
if($next.length==0) $next = $('#news li:first');
$active.stop(true, true);
$active.fadeOut('slow', function() {$active.removeClass('showHeadline');});
setTimeout(function(){$next.fadeIn('slow', function(){$next.addClass('showHeadline');})}, 1000);
if(isPaused == true){
}
else{
startScroll()
}
};
受Jon Raasch's A Simple jQuery Slideshow.的启发 基本上,找到可见的,接下来应该看到的内容,使可见的东西淡化并删除将其标记为可见的类,然后淡入下一个并添加使其可见的类。
现在,如果自动滚动正在运行,那么一切都很糟糕,每三秒就开始一次tickForward()。但是,如果用户反复单击箭头按钮,则会产生两个负面条件:
我可以看到这些情况发生(特别是#2),因为tickForward()函数可以与自身同时运行,产生不同的$ active和$ next。
所以我认为我的问题是: 防止并发执行tickForward()方法的最佳方法是什么?
我尝试或考虑过的一些事情:
设置标志:当tickForward()运行时,它会将isRunning标志设置为true,并在结束前将其设置为false。如果isRunning为false,则事件处理程序的逻辑设置为仅调用tickForward()。我尝试了一个简单的实现,isRunning似乎永远不会改变。
jQuery队列():我认为排队tickForward()命令会很有用,所以如果你快速点击它五次,它仍会按照命令运行,但不会同时运行。但是,在我粗略阅读这个主题时,似乎必须将队列附加到其队列所适用的对象上,并且由于我的tickForward()方法影响多个lis,我不知道我在哪里附加它。
答案 0 :(得分:1)
您可以设置bool变量并在函数执行时检查它的值。如果它已经运行你可以等待它结束或者只是跳过它(不知道哪个是可取的)
var active = false;
function tickForward() {
if (!active) {
active = true;
// your function code goes here
// remember to change active to false once you're done
active = false;
} else {
// if you want to skip if active = true you don't need this else
// if you want to call your method later use something like this
setTimeout(tickForward, 1000);
}
}
答案 1 :(得分:1)
你不能在javascript中拥有函数的并发执行。你只需要几个调用等待执行的顺序执行。因此,在函数运行时设置标志不起作用。当事件处理程序运行时,它不能与tickHandler()执行同时运行(javascript是无线程的)。
现在你必须准确定义你想要的东西,因为它没有出现在你的问题中。当用户快速连续点击箭头时,你会发生什么?点击如何干扰自动滚动?
我认为最简单的方法是仅在代码空闲时处理点击,因此连续3次点击只会勾选一次。并且您点击替换自动滚动并重置其计时器。所以我使用了一个标记ticksInQueue
,当一个标记排在一边排队时,它会被抬起,只有当fadeIn完成时才降低 :
var ticksInQueue = 0,
timerId = setInterval(tickForward, 5000),
isPaused = false;
function tickForward() {
var $active = $('#news li.showHeadline');
var $next = $active.next();
if($next.length==0) $next = $('#news li:first');
$active.stop(true, true);
$active.fadeOut('slow', function() {
$active.removeClass('showHeadline');
});
setTimeout(function(){
$next.fadeIn('slow', function(){
$next.addClass('showHeadline');
if(ticksInQueue) ticksInQueue--; // only change
})}, 1000);
if(isPaused == true){
} else {
startScroll()
}
}
$('#arrow').click(function () {
if(ticksInQueue) return;
ticksInQueue++;
clearInterval(timerId);
timerId = setInterval(tickForward, 5000);
tickForward();
});
您可以在此处尝试演示:http://jsfiddle.net/mhaCF/
答案 2 :(得分:0)
此实现使用“new Date()”和“setTimeout”来避免某些资源的某些竞争条件(并发执行)。这样每次调用“NoConcurrExecFunc”的时间至少相差750毫秒!
{{1}}