setTimeout / clearTimeout problemy

103

Staram się, aby strona przechodziła do strony startowej po np. 10 sekund bezczynności (użytkownik nigdzie nie klikał). Do reszty używam jQuery, ale set / clear w mojej funkcji testowej to czysty javascript.

W mojej frustracji skończyło się na czymś takim, jak ta funkcja, którą miałem nadzieję, że mogę wywołać każde kliknięcie na stronie. Timer uruchamia się prawidłowo, ale nie jest resetowany jednym kliknięciem. Jeśli funkcja zostanie wywołana 5 razy w ciągu pierwszych 10 sekund, pojawi się 5 alertów ... no clearTimeout ...

function endAndStartTimer() {
    window.clearTimeout(timer);
    var timer;
    //var millisecBeforeRedirect = 10000; 
    timer = window.setTimeout(function(){alert('Hello!');},10000); 
}

Ktoś ma jakieś linie kodu, które załatwią sprawę? - po każdym kliknięciu zatrzymaj, zresetuj i uruchom stoper. - Gdy zegar uderza np. 10 sekund zrób coś.

Tillebeck
źródło

Odpowiedzi:

226

Musisz zadeklarować timer poza funkcją. W przeciwnym razie przy każdym wywołaniu funkcji otrzymasz zupełnie nową zmienną.

var timer;
function endAndStartTimer() {
  window.clearTimeout(timer);
  //var millisecBeforeRedirect = 10000; 
  timer = window.setTimeout(function(){alert('Hello!');},10000); 
}
Spiczasty
źródło
plus 1, ponieważ w tym przypadku konieczne jest wyczyszczenie zmiennej, która blokuje timeOut, przed wywołaniem czasu, w ten sposób, unikając dwukrotnego wywołania
Diego Favero
46

Problem polega na tym, że timerzmienna jest lokalna, a jej wartość jest tracona po każdym wywołaniu funkcji.

Musisz ją utrwalić, możesz umieścić ją poza funkcją lub jeśli nie chcesz ujawniać zmiennej jako globalnej, możesz ją przechowywać w domknięciu , np:

var endAndStartTimer = (function () {
  var timer; // variable persisted here
  return function () {
    window.clearTimeout(timer);
    //var millisecBeforeRedirect = 10000; 
    timer = window.setTimeout(function(){alert('Hello!');},10000); 
  };
})();
CMS
źródło
15

Dzieje się tak, ponieważ timer jest lokalną zmienną twojej funkcji.

Spróbuj utworzyć go poza funkcją.

arclight
źródło
6

Sposób wykorzystania tego w reakcji:

class Timeout extends Component {
  constructor(props){
    super(props)

    this.state = {
      timeout: null
    }

  }

  userTimeout(){
    const { timeout } = this.state;
    clearTimeout(timeout);
    this.setState({
      timeout: setTimeout(() => {this.callAPI()}, 250)
    })

  }
}

Przydatne, jeśli chcesz na przykład wywołać interfejs API dopiero po tym, jak użytkownik przestanie pisać. Funkcja userTimeout może być powiązana przez onKeyUp z wejściem.

zero_cool
źródło
1
Właśnie tego szukałem od kilku godzin, dzięki. Zastanawiałem się tylko, czy istnieje lepszy sposób na osiągnięcie takiego wyniku?
Nikasv
1
@nikasv throttling i debouncing to dwie alternatywy: medium.com/@_jh3y/ ...
zero_cool
2

Nie jestem pewien, czy to narusza jakąś dobrą praktykę kodowania, ale zwykle wychodzę z tego:

if(typeof __t == 'undefined')
        __t = 0;
clearTimeout(__t);
__t = setTimeout(callback, 1000);

Zapobiega to konieczności deklarowania licznika czasu poza funkcją.

EDYCJA: to również nie deklaruje nowej zmiennej przy każdym wywołaniu, ale zawsze przetwarza to samo.

Mam nadzieję że to pomoże.

clamiax
źródło
0

To działa dobrze. To menedżer, którego stworzyłem do obsługi imprez typu hold. Ma wydarzenia do wstrzymania i kiedy odpuszczasz.

function onUserHold(element, func, hold, clearfunc) {
    //var holdTime = 0;
    var holdTimeout;

    element.addEventListener('mousedown', function(e) {
        holdTimeout = setTimeout(function() {
            func();
            clearTimeout(holdTimeout);
            holdTime = 0;
        }, hold);
        //alert('UU');
    });

    element.addEventListener('mouseup', clearTime);
    element.addEventListener('mouseout', clearTime);

    function clearTime() {
        clearTimeout(holdTimeout);
        holdTime = 0;
        if(clearfunc) {
            clearfunc();
        }
    }
}

Parametr elementu to ten, który trzymasz. Parametr func jest uruchamiany, gdy utrzymuje się przez liczbę milisekund określoną przez parametr hold. Parametr clearfunc jest opcjonalny i jeśli zostanie podany, zostanie uruchomiony, jeśli użytkownik puści element lub go opuści. Możesz też obejść ten problem, aby uzyskać żądane funkcje. Cieszyć się! :)

Kino Bacaltos
źródło
0

Praktyczny przykład Używanie Jquery do rozwijanego menu! Po najechaniu kursorem na #IconLoggedinUxExternal wyświetla div # ExternalMenuLogin i ustawia limit czasu, aby ukryć div # ExternalMenuLogin

Po najechaniu kursorem na div # ExternalMenuLogin anuluje limit czasu. Po wyjechaniu kursorem myszy na div # ExternalMenuLogin ustawia limit czasu.

Chodzi o to, aby zawsze wywołać clearTimeout przed ustawieniem limitu czasu, aby uniknąć podwójnych wywołań

var ExternalMenuLoginTO;
$('#IconLoggedinUxExternal').on('mouseover mouseenter', function () {

    clearTimeout( ExternalMenuLoginTO )
    $("#ExternalMenuLogin").show()
});

$('#IconLoggedinUxExternal').on('mouseleave mouseout', function () {

    clearTimeout( ExternalMenuLoginTO )    
    ExternalMenuLoginTO = setTimeout(
        function () {

            $("#ExternalMenuLogin").hide()

        }
        ,1000
    );
    $("#ExternalMenuLogin").show()
});

$('#ExternalMenuLogin').on('mouseover mouseenter', function () {

    clearTimeout( ExternalMenuLoginTO )
});
$('#ExternalMenuLogin').on('mouseleave mouseout', function () {

    clearTimeout( ExternalMenuLoginTO )
    ExternalMenuLoginTO = setTimeout(
        function () {

            $("#ExternalMenuLogin").hide()

        }
        ,500
    );
});
Diego Favero
źródło