【问题标题】:clearTimeout doesn't clear the timeout variableclearTimeout 不清除超时变量
【发布时间】:2017-07-10 02:18:43
【问题描述】:

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

问题是当我调试时,我看到超时变量没有清除超时。单击“确定”后,计时器重置为 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>

【问题讨论】:

  • 看看你的 setTimeout 线......你没有正确使用它
  • 我如何以不同的方式使用它?我在另一个堆栈溢出帖子上看到了这个例子。
  • setTimeout() 函数的第一个参数必须是函数引用。您正在调用.dialog('open')立即并将其返回值传递给setTimeout()

标签: javascript jquery dialog settimeout cleartimeout


【解决方案1】:

正如所写,

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

timer() 可以简化为:

  • timer() 之外的函数中定义对话框设置。
  • timer() 之外的函数中定义倒数计时器计算/显示。
  • 引入了第三个计时器来管理 28 分钟的持续时间 - 这避免了在时间显示功能中测试 if (distance &lt; 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);
};

【讨论】:

    【解决方案2】:

    例如:

    function open() {
      $("#alert div").dialog("open");
     }
    
     timeout = setTimeout(open, 120000);
    

    【讨论】:

    • 这仍然没有得到第二次显示的警报。它显示一次,我单击确定,计时器刷新但当它达到 0 时,它再次调用 setTimeout 但不显示警报对话框。
    【解决方案3】:

    问题是,一旦你实例化了一个.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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-18
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2023-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多