Тайм-аут JavaScript срабатывает 3 раза вместо одного раза (clearTimeout не работает?)
Я хочу запустить ajax-действие, когда пользователь делает паузу при наборе текста (а не после каждого нажатия). Поэтому я сделал что-то вроде этого:
Когда пользователь перестает печатать после 3 секунд выполнения незанятой функции, она должна выполняться... (это - но почему 3 раза для длинных фраз - я ожидаю, что она будет работать только один раз, так как я очищаю таймаут после каждого нажатия клавиши). В чем проблема?
var timer;
var interval = 3000;
$('#inp').keyup(function() {
timer = setTimeout(done, interval);
});
$('#inp').keydown(function() {
clearTimeout(timer)
});
function done() {
console.log('ajax');
}
Рабочий пример на jsfiddle:
http://jsfiddle.net/vtwVH/
Ответы
Ответ 1
Проблема в том, что вы переписываете переменную timer
в событие keydown.
Итак, если вы нажмете еще одну клавишу до того, как вычеркнет Timout, например, держите клавишу
Ссылка на timeOut потеряна, и вы не сможете ее снова очистить.
Чтобы исправить это, вы можете просто очистить и установить таймер в событии keyUp
, например
var timer;
var interval = 3000;
$('#inp').keyup(function(e){
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(done, interval);
});
function done() {
console.log('ajax');
}
Здесь работает fiddle
Ответ 2
Когда вы печатаете, вы можете иногда нажать еще одну клавишу, прежде чем отпускать первую. Вы можете этого не заметить, особенно если вы печатаете длинную фразу. В этом случае порядок событий не down up down up
, а down down up up
, и поэтому будут установлены два тайм-аута.
Более согласованно очищать таймаут непосредственно перед его установкой (в том же обработчике событий).
Ответ 3
События, похоже, не следуют строгим последовательным правилам, второй ввод ключей происходит раньше, чем первая клавиатура, поэтому таймер инициализируется несколько раз.
Попробуйте этот мод:
$('#inp').keyup(function(){
clearTimeout(timer);
timer = setTimeout(done, interval);
});
Ответ 4
Просто убедитесь, что вы очистили интервал:
var timer;
var interval = 3000;
$('#inp').keyup(function(){
clearTimeout(timer)
timer = setTimeout(done, interval);
});
$('#inp').keydown(function(){
clearTimeout(timer)
});
function done() {
console.log('ajax');
}
JSFiddle
Ответ 5
Если пользователь не набирает очень медленно, keydown
и keyup
не будут поступать так, как вы думаете. Например, вы можете получить два события keydown
, за которыми следуют два события keyup
. Если вы не справитесь с этим, второе событие keyup
запустит другой таймер и перезапишет ссылку на первый таймер, чтобы он не очистился.
Следите за тем, выполняется ли тайм-аут, и очистите его в keyup
, если он запущен:
var timer = null;
var interval = 3000;
$('#inp').keyup(function(){
if (timer != null) {
window.clearTimeout(timer)
}
timer = window.setTimeout(done, interval);
});
$('#inp').keydown(function(){
if (timer != null) {
window.clearTimeout(timer);
timer = null;
}
});
function done() {
timer = null;
console.log('ajax');
}
Демо: http://jsfiddle.net/Guffa/vtwVH/3/