clearTimeout не очищает переменную тайм-аута

У меня есть приложение, которое должно быть отключено через 28 минут. Он покажет диалоговое окно jQuery в течение 2 минут. Если пользователь нажимает «ОК» в течение двух минут, таймер обновляется до 28 минут, и когда обратный отсчет достигает 0 минут, он должен снова отобразить диалоговое окно jQuery.

Проблема в том, что когда я отлаживаю, я вижу, что переменная тайм-аута не очищает тайм-аут. После того, как я нажимаю «ОК», таймер сбрасывается до 28 минут, но setTimeout больше не отображает диалоговое окно, когда обратный отсчет достигает 0 минут.

Вот мой код:

var timeout;
function timer() {
countDownDate = 0;
    console.log("Hello");
    countDownDate = 0;
    var timeExpires = new Date().getTime();
    countDownDate = timeExpires + 1680000;
    now = 0;
    distance = 0;
    if(timeout){
    clearTimeout(timeout);
    }
    // Update the count down every 1 second
    var x = setInterval(function () {

        // Get todays date and time
         now = new Date().getTime();

        // Find the distance between now an the count down date
         distance = countDownDate - now;

        // Time calculations for days, hours, minutes and seconds
        var days = Math.floor(distance / (1000 * 60 * 60 * 24));
        var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
        var seconds = Math.floor((distance % (1000 * 60)) / 1000);

        if (distance < 0) {
        if ($("#alert").length) {
            var title;
            if ($("#alert span").length) {
                title = $("#alert span").text();
            }
            $("#alert div").dialog({
                title: title,
                modal: true,
                buttons: {
                    Ok: function() {
                        var foo = $(this);
                        clearTimeout(timeout);
                        timer();
                        foo.dialog('close');
                    },
                    Cancel: function() {
                      esriId.destroyCredentials();
                      window.location.replace(redirect_uri);
                    }
                  }/*,
                open: function() {
                    var foo = $(this);
                    timeout = setTimeout(function() {
                        foo.dialog('close');
                        esriId.destroyCredentials();
                        window.location.replace(redirect_uri);
                    }, 120000);
                },*/

            });
            }
            timeout = setTimeout($("#alert div").dialog("open"), 120000);
            clearInterval(x);
        }
    }, 1000);
};

Вот HTML div для оповещения:

<div id="alert" style="display:none">
            <span>You will be signed out</span>
            <div>You will be signed out due to inactivity on the page. If you wish to stay on the page, please press 'Ok'</div>
        </div>

person Palak    schedule 10.07.2017    source источник
comment
Посмотрите на свою строку setTimeout.... вы используете ее неправильно   -  person Patrick Evans    schedule 10.07.2017
comment
Как использовать его по-другому? Я видел этот пример в другом сообщении о переполнении стека.   -  person Palak    schedule 10.07.2017
comment
Первый аргумент функции setTimeout() должен быть ссылкой на функцию. Вы вызываете .dialog('open') немедленно и передаете возвращаемое значение в setTimeout().   -  person nnnnnn    schedule 10.07.2017


Ответы (3)


Как написано,

  • Команда setTimeout() построена неправильно.
  • кажется, вы хотите открыть диалоговое окно по истечении 28 минут и автоматически закрыть его еще через 2 минуты, если не нажата кнопка «ОК»; но вы используете этот двухминутный таймер, чтобы открыть диалоговое окно, а не закрыть его.
  • трудно увидеть лес за деревьями внутри timer().

timer() можно упростить:

  • определение настройки диалога в функции вне timer().
  • определение расчета/отображения таймера обратного отсчета в функции вне timer().
  • введение третьего таймера для управления 28-минутной продолжительностью - это позволяет избежать необходимости проверки if (distance < 0) и т. д. в функции отображения времени.

Вот исправленный код:

// set up the dialog
function showDialog(callback) {
    $("#alert div").dialog('destroy').dialog({
        title: $("#alert span").length ? $("#alert span").text() : '---',
        modal: true,
        buttons: {
            Ok: function() {
                $(this).dialog('close');
                callback('ok')
            },
            Cancel: function() {
                // $(this).dialog('close'); // ?
                callback('cancel');
            }
        }
    }).dialog('open');
}

// function for calculating and displayig the countdown values
function displayCountdown(t) {
    var distance = Math.max(0, t - Date.now());
    var days = Math.floor(distance / (1000 * 60 * 60 * 24));
    var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
    var seconds = Math.floor((distance % (1000 * 60)) / 1000);
    // ... display days, hours, minutes, seconds somewhere
}

// object which defines the three timers
var timers = {
    'ticker':     { 'ref': null, 't': 1000 }, // 1 second
    'stopTicker': { 'ref': null, 't': 1680000}, // 28 minutes
    'cancelDialog': { 'ref': null, 't': 120000 } // 2 minutes
}

function redirect() {
    esriId.destroyCredentials();
    window.location.replace(redirect_uri);
}

// 
function timer() {
    clearInterval(timers.ticker.ref);
    clearTimeout(timers.stopTicker.ref);
    clearTimeout(timers.cancelDialog.ref);
    timers.stopTicker.ref = setTimeout(function() {
        clearInterval(timers.ticker.ref);
        showDialog(function(outcome) {
            if(outcome === 'ok') {
                timer();
            } else {
                redirect();
            }
        });
        timers.cancelDialog.ref = setTimeout(redirect, timers.cancelDialog.t);
    }, timers.stopTicker.t);

    timers.ticker.ref = setInterval(displayCountdown.bind(null, Date.now() + timers.stopTicker.t), timers.ticker.t);
};

Обратите внимание, что redirect() будет вызываться двумя возможными способами:

  1. в ответ на отмену диалога.
  2. в связи с истечением 2 мин.

Обратный вызов, переданный в showDialog(), не является строго обязательным, но позволяет диалогу быть полностью независимым от последствий его результата. Вся эта логика находится в вызывающей программе timer().


Другой, возможно, более чистый подход — обещать диалог.

Здесь все остается так же, как указано выше, кроме showDialog() и timer().

// set up a promisified dialog
function showDialog() {
    return $.Deferred(function(dfrd) {
        $("#alert div").dialog('destroy').dialog({
            'title': $("#alert span").length ? $("#alert span").text() : '---',
            'modal': true,
            'buttons': {
                'Ok': dfrd.resolve, // yay!
                'Cancel': dfrd.reject // yay!
            }
        }).dialog('open');
    }).always(function() {
        $("#alert div").dialog('close');
    });
}

function timer() {
    clearTimeout(timers.ticker.ref);
    clearTimeout(timers.stopTicker.ref);
    clearTimeout(timers.cancelDialog.ref);
    timers.stopTicker.ref = setTimeout(function() {
        clearInterval(timers.ticker.ref);
        $.Deferred(function(dfrd) { // "race" pattern
            showDialog().then(dfrd.resolve, dfrd.reject);
            timers.cancelDialog.ref = setTimeout(dfrd.reject, timers.cancelDialog.t);
        }).then(timer, redirect); // yay-yay!
    }, timers.stopTicker.t);

    timers.ticker.ref = setInterval(displayCountdown.bind(null, Date.now() + timers.stopTicker.t), timers.ticker.t);
};
person Roamer-1888    schedule 10.07.2017

Например:

function open() {
  $("#alert div").dialog("open");
 }

 timeout = setTimeout(open, 120000);
person Dom    schedule 10.07.2017
comment
Это все еще не показывает предупреждение, чтобы показать второй раз. Он отображается один раз, я нажимаю «ОК», таймер обновляется, но когда он достигает 0, он снова вызывает setTimeout, но не показывает диалоговое окно предупреждения. - person Palak; 10.07.2017