Squ*_*Cat 6 javascript jquery timeout settimeout
简单的场景
我有一个列表,我使用箭头键(向上,向下)实现浏览,并且在当前列表项的每次更改时,数据库对象通过AJAX加载.
甜.
问题
当用户非常快速地浏览列表时,我不希望每个请求都消失.但当然,原始请求应立即生效.
我的想法是使用变量作为延迟设置超时,并在项目的初始加载后,增加该变量.
这是有效的,但当用户停止浏览一小段时间,但随后继续,我仍然不希望每个请求都关闭.
所以我想,每次浏览事件都必须合理地增加延迟变量,直到达到阈值.
这种有机方法可以成功地减少不必要的物品装载量.
我的解决方案
我走了很远.这段代码(下面的解释)将完成这项工作,其中一个主要原因是:
在第一次浏览完成然后停止后,延迟将自动保持在(第二步)最小值150ms.
当然我试图解决这个问题,但正如你将看到的,这是一个有趣但可能相当常见的逻辑问题 - 我认为我的整体方法是错误的.
但我不知道如何.大脑无法计算.电脑说没有.
码
您可以筛选我给出的示例,也可以在jsFiddle中找到一个功能齐全的模拟器.
如果你选择jsFiddle:
单击按钮,立即显示项目加载.现在稍等一下,再次单击该按钮,初始加载将被延迟.如果您持续快速按下按钮,则只有在您完成点击过程后才会显示项目加载.
代码示例
我们在一个对象字面内,只是你知道.
_clickTimer: false, // holds what setTimeout() returns
_timerInc: 0, // the your timer delay are belong to us
/**
* Function is triggered whenever the user hits an arrow key
* itemRef is the passed list item object (table row, in this case)
*/
triggerItemClick: function(itemRef){
var that=this;
var itemId=$(itemRef).data('id'); // Get the item id
if(this._clickTimer){ // If a timeout is waiting
clearTimeout(this._clickTimer); // we clear it
this._itemClickTimer=false; // and reset the variable to false
/**
* Note that we only arrive here after the first call
* because this._clickTimer will be false on first run
*/
if(this._timerInc == 0){ // If our timer is zero
this._timerInc = 150; // we set it to 150
} else { // otherwise
if(this._timerInc <= 350) // we check if it is lower than 350 (this is our threshold)
this._timerInc += 15; // and if so, we increase in steps of 15
}
}
/**
* Regardless of any timing issues, we always want the list
* to respond to browsing (even if we're not loading an item.
*/
this.toggleListItem(itemId);
/**
* Here we now set the timeout and assign it to this._clickTimer
*/
this._clickTimer=setTimeout(function(){
// we now perform the actual loading of the item
that.selectItem(itemId);
// and we reset our delay to zero
that._timerInc=0;
}, this._timerInc); // we use the delay for setTimeout()
}
Run Code Online (Sandbox Code Playgroud)
说明
在第一次通话:_clickTimer是false,_timerInc是0的,所以第一次调用会导致延迟0的setTimeout()和_clickTimer将被设置.该项目将立即加载.
第二次调用 - 假设我们的超时仍在等待触发,则_clickTimer清除,延迟设置为150if 0或者15如果低于350(阈值)则增加.
如果你继续浏览,这很好用.计时器增加,只有在您停止浏览一段时间后才会触发加载.
但是你停止后,下次你继续的时候,_clickTimer会不会是假的(因为setTimeout()一个计数器分配给它),这样反过来_timerInc会被设置为150的时候了.因此,第一次浏览将导致在加载任何内容之前延迟150ms.
叫我疯狂或挑剔,但目标是没有这种延迟.
当然你会说:simple,_clickTimer在setTimeout()闭包结束时设置为false ,因此一旦浏览完成并且项目被加载就会重置.太好了,但这会导致延迟永远不会超过0ms.想一想,你会看到.
我希望这个问题得到了恰当的解释,并且有人的大脑比我的更有能力找到解决方案.
使用Promises可能可以以非常复杂的方式做到这一点。由于这主要是糖衣,但我认为一定可以直接解决这个问题,我想我做到了。
更新了小提琴。我在文本中添加了延迟,这样我更容易调试东西,并且还做了一些小的整理,但我的实际更改非常小。下面对此进行详细介绍。
你在最后的评论是我的第一直觉:
当然你会说:简单,
_clickTimer在关闭结束时设置为 falsesetTimeout(),这样一旦浏览完成并加载项目后它就会重置。很好,但这会导致延迟永远不会超过 0 毫秒。
事实上,这将使延迟永远不会超过 0,因为我们不能那么快地点击(或在实际应用程序中浏览那么快)。但是...如果我们只在延迟不为 0 时才重置怎么办?因此,如果超时发生,但仅在 0 毫秒后发生,我们就会记住发生了超时。如果晚于该时间,则一定发生了浏览的实际暂停。通过在超时回调中添加几行,可以轻松实现这一点,如下所示。
this._clickTimer = setTimeout(function() {
// we now perform the actual loading of the item
that.selectItem();
// and we reset our delay to zero
if (that._timerInc > 0) {
that._clickTimer = false;
}
that._timerInc = 0;
}, this._timerInc); // we use the delay for setTimeout()
Run Code Online (Sandbox Code Playgroud)
它似乎完全按照你想要的方式工作,除了现在,如果你在点击之间等待足够长的时间,延迟将是 0 毫秒,然后是 150 毫秒,然后是 0 毫秒,等等。这可以通过添加额外的超时来解决,以防延迟为0 毫秒,但仍会重置延迟。每当触发发生时(在演示中单击,在应用程序中浏览),此超时就会被取消。
我相信,这一切都会让一切按照你想要的方式运作。为了完整起见,我还在此处包含上述小提琴作为片段。
this._clickTimer = setTimeout(function() {
// we now perform the actual loading of the item
that.selectItem();
// and we reset our delay to zero
if (that._timerInc > 0) {
that._clickTimer = false;
}
that._timerInc = 0;
}, this._timerInc); // we use the delay for setTimeout()
Run Code Online (Sandbox Code Playgroud)
var _simulator = {
_clickTimer: false, // holds what setTimeout() returns
_cancelClickTimer: false,
_timerInc: 0, // the your timer delay are belong to us
/**
* Function is triggered whenever the user hits an arrow key
* itemRef is the passed list item object (table row, in this case)
*/
triggerItemClick: function() {
var that = this;
// always cancel resetting the timing, it can never hurt
clearTimeout(that._cancelClickTimer);
that._cancelClickTimer = false;
if (this._clickTimer) { // If a timeout is waiting
clearTimeout(this._clickTimer); // we clear it
this._clickTimer = false; // and reset the variable to false
/**
* Note that we only arrive here after the first call
* because this._clickTimer will be false on first run
*/
if (this._timerInc == 0) { // If our timer is zero
this._timerInc = 150; // we set it to 150
} else { // otherwise
if (this._timerInc <= 350) // we check if it is lower than 350 (this is our threshold)
this._timerInc += 15; // and if so, we increase in steps of 15
}
}
/**
* Regardless of any timing issues, we always want the list
* to respond to browsing (even if we're not loading an item.
*/
this.toggleListItem();
/**
* Here we now set the timeout and assign it to this._clickTimer
*/
this._clickTimer = setTimeout(function() {
// we now perform the actual loading of the item
that.selectItem();
// and we reset our delay to zero
if (that._timerInc > 0) {
that._clickTimer = false;
} else {
that._cancelClickTimer = setTimeout(function() {
that._clickTimer = false;
}, 150);
}
that._timerInc = 0;
}, this._timerInc); // we use the delay for setTimeout()
},
/** the following functions are irrelevant for the problemsolving above **/
toggleListItem: function() {
$('#status').prepend($('<div />').text('You toggled a list item ... in ' + this._timerInc + ' ms'));
},
selectItem: function(id) {
$('#loader').show();
setTimeout(function() {
$('#loader').hide();
}, 800);
}
};
$('#clickZone').on('click', function() {
_simulator.triggerItemClick();
});Run Code Online (Sandbox Code Playgroud)
#clickZone {
background: #369;
color: #fff;
width: 420px;
height: 80px;
text-align: center;
line-height: 80px;
cursor: pointer;
-ms-user-select: none;
-moz-user-select: -moz-none;
-webkit-user-select: none;
user-select: none;
font-family: Arial;
}
#status {
line-height: 20px;
margin-top: 10px;
font-family: Arial;
font-size: 12px;
background: #936;
color: #fff;
padding: 7px 10px;
}
#status > div {
padding: 2px 0 4px;
border-bottom: 1px dashed #ddd;
}
#status > div:last-child {
border-bottom: 0;
}
#loader,
#notice {
display: none;
margin-top: 10px;
width: 320px;
padding: 10px 15px;
background: #ddd;
font-family: Arial;
font-size: 11px;
text-align: center;
}
#notice {
background: lightblue;
font-size: 14px;
color: #333;
}Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
118 次 |
| 最近记录: |