setTimeout 立即运行,而不是等待延迟值

Posted

技术标签:

【中文标题】setTimeout 立即运行,而不是等待延迟值【英文标题】:setTimeout runs immediately instead of waiting the delay value 【发布时间】:2017-01-26 22:18:00 【问题描述】:

我非常困惑。为什么这个程序不使用我得到的我命名为“结果”的延迟数。它应该用用户发布的未来日期减去当前时间。这最终会成为一个警报。 看看,运行代码。

            // Set a future time you want the alert() function to go off
            var eta_ms = new Date(2017, 1, 26, 17, 06).getTime();
    
            document.write(Date.now() + "<br />");
            document.write(eta_ms + "<br />");
    
            var result = eta_ms - Date.now();
            document.write("The Delay: " + result + "<br />" );
            document.write(result + "<br />");
            document.write(typeof (result) + "<br />");
    
            setTimeout(function() alert("Hello"); , result);

【问题讨论】:

开发者工具控制台有错误吗? 【参考方案1】:

只需设置第 0 个月(日期构造函数的第二个参数),它就会按预期工作。

请注意,当您在 23:35 (26.01.2017) 之后运行此代码时,result 会变为负数,因为您必须在将来始终设置 eta_ms

希望这会有所帮助:

    var eta_ms = new Date(2017, 0, 26, 23, 35).getTime();
    document.write(Date.now() + "<br />");
    document.write(eta_ms + "<br />");

    var result = eta_ms - Date.now();
    document.write("The Delay: " + result + "<br />" );
    document.write(result + "<br />");
    document.write(typeof (result) + "<br />");

    setTimeout(function() alert("Hello"); , result);

为了避免设置第 0 个月,更好的方法可能是以另一种方式设置未来时间 (eta_ms),以便有人只需更改此 minutesInFuture 变量以更改 eta_ms。以这种方式,eta_ms 不仅限于一月:

    var minutesInFuture = 5;

    var eta_ms = new Date().getTime();
    eta_ms = eta_ms + minutesInFuture * 1000 * 60;

    document.write(Date.now() + "<br />");
    document.write(eta_ms + "<br />");

    var result = eta_ms - Date.now();
    document.write("The Delay: " + result + "<br />" );
    document.write(result + "<br />");
    document.write(typeof (result) + "<br />");

    setTimeout(function() alert("Hello"); , result);

(第 0 个月)作为其状态 here

【讨论】:

有关更多信息,请仔细检查哪些 Date 属性是基于 0 的,哪些是基于 1 的:w3schools.com/jsref/jsref_obj_date.asp 那么,如果 OP 将这一行更改为:var result = Date.now() - eta_ms; 并希望将 2/1/2017 用作 result,这个答案会有帮助吗? 所以,我想我的意思是,将月份更改为 0 确实不是一个答案。这是对 OP 没有要求的数据的手动调整。如果 OP 真的意味着 2/26/2017 怎么办? @ScottMarcus:你是绝对正确的。它应该尽可能灵活。希望我的第二部分做得更好。 我看不出您调整后的代码如何以任何方式解决问题。它只是移动了一些值。如果您想从现在开始一个月的闹钟,完全相同的问题仍然存在。【参考方案2】:

JavaScript 使用 32 位整数来存储延迟值。这使得您可以使用的最大值为 2147483647。

这意味着您可以拥有的最长setTimeoutsetInterval 延迟为 2,147,483,647 毫秒或 24.85513480324074 天。

您的值最终为 2,677,448,064,即从现在起 31 天(new Date(2017, 1, 26, 17, 06) 是 2017 年 2 月 26 日),这大于最大值,因此它会尽快崩溃并运行。

如果您确实打算将其用作一个长期计时器,并且即使 setTimeout 没有最大值,这也只有在用户始终在浏览器中保持您的页面打开时才有效他们正在等待警报。

长期计时器的更好解决方案是在 localStorage 和页面上存储警报应该响起的时间(而不是从现在到那时的时间量)加载,取出该值并将其与当前时间进行比较。

【讨论】:

@AhmedAhmed 这应该是答案。不是告诉您如何修复代码,而是告诉您确切为什么会出现问题。 帮助阅读你的答案是明智的,我学到了一些关于 setTimeout 或 setInterval 的最大值的新知识。你是对的,请不要误会我的意思,只是一个问题:在这个例子中将未来时间设置为下个月,这很有可能吗?或者换句话说,超过 setTimeout 或 setInterval 的最大值。 @Blauharley 未来的警报时间是否可能需要整整一个月?当然,为什么不呢。您可以完成这项工作,但您将无法使用setTimout 来完成这项工作。而且,即使你可以,它也只有在用户在等待的整个过程中保持浏览器打开的情况下才会起作用。长期计时器的更好解决方案是将闹钟时间存储在 localStorage 中,并在页面加载时取出该值并将其与当前时间进行比较。 @ScottMarcus 知道我是否希望警报超过 24 天真的很有趣。【参考方案3】:

因为 javascript 中的月份是从 0 开始的。所以第一个月是二月。我相信这个疯狂的特性是从 Java 中借来的。

【讨论】:

答案如何?如果 OP 试图在 2/26/17 发出警报怎么办?

以上是关于setTimeout 立即运行,而不是等待延迟值的主要内容,如果未能解决你的问题,请参考以下文章

setTimeout 在 forEach 中不起作用

$ timeout立即运行,而不是等待超时

SetTimeout直接执行没有延时

如何要求信号量立即返回而不是等待信号?

setTimeout 函数执行代码没有任何延迟。 Javascript [重复]

SpringBoot:RabbitMQ 延迟队列