clearTimeout 不清除超时变量

clearTimeout doesn't clear the timeout variable

我有一个应用程序需要在 28 分钟后超时。它将显示 jQuery 对话框 2 分钟。如果用户在两分钟内单击 "Ok",计时器将刷新为 28 分钟,当倒计时达到 0 分钟时,它应该再次显示 jQuery 对话框。

问题是当我调试时,我看到超时变量没有清除超时。单击 "Ok" 后,计时器重置为 28 分钟,但当倒计时达到 0 分钟时,setTimeout 不会再次显示对话框。

这是我的代码:

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>

例如:

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

 timeout = setTimeout(open, 120000);

事情是,一旦你实例化一个 .dialog(),它使用 spandiv

所以你必须刷新那些。
我让它在这个 CodePen 中工作。 (我为了测试缩短了时间)

timer()函数之前,添加:

var alertHTML = $("#alert").html();

那么,在函数中,技巧就在这里:

var title;
if ($("#alert div").length) {
  console.log("alert is present");
}else{
  console.log("alert is missing");
  $("#alert").html(alertHTML);
}
title = $("#alert span").text();

如所写,

  • setTimeout() 命令构造错误。
  • 您似乎想在 28 分钟到期时打开对话框,如果未单击“确定”,则在 2 分钟后自动关闭它;但是您正在使用那个 2 分钟计时器来 打开 对话框,而不是 关闭 它。
  • 里面只见树木不见林timer()

timer() 可以简化为:

  • timer() 之外的函数中定义对话框设置。
  • timer() 之外的函数中定义倒计时器 calcs/display。
  • 引入第三个计时器来管理 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);
};