在 JavaScript 中,如何让函数在特定时间运行?

IT技术 javascript time intervals
2021-03-12 01:24:31

我有一个托管仪表板的网站:我可以编辑页面上的 JavaScript,目前我每五秒刷新一次。

我现在正在尝试window.print()每天早上 8 点运行。

我怎么能这样做?

5个回答

JavaScript不是用于此的工具。如果你想在每天的特定时间运行某样东西,你几乎肯定会寻找在本地运行的东西,比如 或者 .


但是,让我们考虑一下 JavaScript 是您唯一的选择。有几种方法可以做到这一点,但我会给你最简单的。

首先,您必须创建一个new Date()并设置检查间隔以查看小时是否为 8(上午 8 点)。

这将每分钟(60000 毫秒)检查一次是否是 8 点:

window.setInterval(function(){ // Set interval for checking
    var date = new Date(); // Create a Date object to find out what time it is
    if(date.getHours() === 8 && date.getMinutes() === 0){ // Check the time
        // Do stuff
    }
}, 60000); // Repeat every 60000 milliseconds (1 minute)

它不会正好8 点钟执行(除非你在这一分钟开始运行它),因为它每分钟检查一次您可以根据需要尽可能减少间隔以提高检查的准确性,但这确实有点矫枉过正:它会检查每天每个小时每一分钟以查看是否是 8 点。

检查的强度是由于 JavaScript 的性质:对于这类事情有更好的语言和框架。因为 JavaScript 在您加载网页时在它们上运行,所以它并不意味着处理持久的、扩展的任务。

还要意识到这需要打开它正在执行的网页也就是说,如果页面没有打开每分钟进行计数和检查,您就不能在每天早上 8 点执行计划的操作

你说你已经每五秒刷新一次页面:如果这是真的,你根本不需要计时器。每次刷新页面时只需检查:

var date = new Date(); // Create Date object for a reference point
if(date.getHours() === 8 && date.getMinutes() === 0 && date.getSeconds() < 10){ // Check the time like above
   // Do stuff
}

有了这个,你还必须检查秒数,因为你每五秒刷新一次,所以你会得到重复的任务。


随着中说,你可能想要做像这样在OS X计划任务或撰写的Automator工作流

如果您需要更多与平台无关的东西,我会认真考虑查看PythonBash


作为更新,OS X Yosemite 引入了JavaScript for Automation,它似乎提供了一种可行的方式来将 JavaScript 用于此类事情(尽管显然您不是在相同的上下文中使用它;Apple 只是给您一个本地使用另一种脚本语言的界面)。

如果您在 OS X 上并且真的想使用 JavaScript,我认为这是要走的路。

与上述链接的发行说明似乎是撰写本文时唯一存在的文档(在优胜美地向公众发布后约 2 个月),但它们值得一读。你也可以看看 一些例子的标签。

我还发现JXA Cookbook 非常有帮助。

您可能需要稍微调整此方法以适应您的特定情况,但我将给出一个总体概述。

  1. 在 Automator 中创建一个空白应用程序。
    • 打开 Automator.app(它应该在您的应用程序目录中)并创建一个新文档。
    • 从对话框中,选择“应用程序”。 Automator 新文档对话框
  2. 添加 JavaScript 操作。
    • 下一步是实际添加将要执行的 JavaScript。为此,首先从侧边栏中向工作流添加“运行 JavaScript”操作。 将 JS 文件拖入工作流
  3. 编写 JavaScript。

    • 这是您在继续之前必须知道自己想要做什么的地方。根据您提供的内容,我假设您想window.print()在 Safari 中加载的页面上执行您可以这样做(或者,更一般地说,在 Safari 选项卡中执行任意 JS):

      var safari = Application('Safari');
      safari.doJavaScript('window.print();', { in: safari.windows[0].currentTab });
      
    • 您可能需要windows根据您的设置调整您正在访问的内容。
  4. 保存应用程序。
    • 文件作为应用程序保存(File -> Save+ S)到您可以找到的位置(或 iCloud)。
  5. 安排它运行。
    • 打开日历(或 iCal)。
    • 创建一个新事件并为其指定一个可识别的名称;然后,将时间设置为所需的运行时间(在本例中为 8:00 AM)。
    • 将事件设置为每天重复(或每周、每月等 - 无论您希望它运行的频率如何)。
    • 将警报(或警报,取决于您的版本)设置为自定义。
    • 选择“打开文件”并选择您保存的应用程序文件。
    • 为警报计时选项选择“事件发生时”。 用于安排活动的 GIF 说明

而已!每次将事件设置为运行时,您在应用程序文件中编写的 JavaScript 代码都会运行。如果需要,您应该能够返回到 Automator 中的文件并修改代码。

我指的是除非用户在特定时间打开页面,否则 JavaScript 不会运行。我担心 OP 会将客户端脚本与预定作业混淆。
2021-04-23 01:24:31
@Christophe 怎么样?如果您指的是它不会在恰好8:00运行的事实,它将在该分钟内的某个时间运行。如果 OP 想要更精确,他/她可以减少间隔,但它是矫枉过正的。
2021-05-13 01:24:31
它很好地使用了 Javascript。将 Node.js 用于这样的本地任务。
2021-05-13 01:24:31
@user3738622 恐怕这将是一个完全不同的问题:我不知道 Perl,所以这将是一个不同的主题,有不同的答案。
2021-05-17 01:24:31
注意:这将在上午 8 点后最多 60 秒触发。和@Christophe,是的,这确实在每天早上 8 点运行(只要页面打开),因为没有取消间隔。
2021-05-20 01:24:31
function every8am (yourcode) {
    var now = new Date(),
        start,
        wait;

    if (now.getHours() < 7) {
        start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0, 0);
    } else {
        start = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 8, 0, 0, 0);
    }

    wait = start.getTime() - now.getTime();

    if(wait <= 0) { //If missed 8am before going into the setTimeout
        console.log('Oops, missed the hour');
        every8am(yourcode); //Retry
    } else {
        setTimeout(function () { //Wait 8am
            setInterval(function () {
                yourcode();
            }, 86400000); //Every day
        },wait);
    }
}

要使用它:

var yourcode = function () {
        console.log('This will print evryday at 8am');
    };
every8am(yourcode);

基本上,获取现在的时间戳,如果及时运行,则获取今天早上8点的时间戳,或者明天早上8点,然后设置24小时的时间间隔每天运行代码。您可以通过将变量 start 设置为不同的时间戳来轻松更改它将运行的小时。

我不知道这样做会有什么用处,正如其他人指出的那样,您需要整天打开页面才能看到这种情况发生......

此外,由于您每 5 秒刷新一次:

function at8am (yourcode) {
    var now = new Date(),
        start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0, 0);

    if (now.getTime() >= start.getTime() - 2500 && now.getTime() < start.getTime() + 2500) {
        yourcode();
    }
}

以与 every8am 相同的方式运行它,它查看 8am 是否提前或落后 2.5 秒,如果是则运行。

我试着给出我的答案,希望它可以帮助:

    function startJobAt(hh, mm, code) {
        var interval = 0;
        var today = new Date();
        var todayHH = today.getHours();
        var todayMM = today.getMinutes();
        if ((todayHH > hh) || (todayHH == hh && todayMM > mm)) {
            var midnight = new Date();
            midnight.setHours(24,0,0,0);
            interval = midnight.getTime() - today.getTime() +
                    (hh * 60 * 60 * 1000) + (mm * 60 * 1000);
        } else {
            interval = (hh - todayHH) * 60 * 60 * 1000 + (mm - todayMM) * 60 * 1000;
        }
        return setTimeout(code, interval);
    }

使用 startJobAt,您只能执行您希望的任务之一,但是如果您需要重新运行您的任务,则由您来调用 startJobAt。

再见

ps

如果您需要自动打印操作,没有对话框,请考虑使用http://jsprintsetup.mozdev.org/reference.html插件用于 mozilla 或其他插件用于其他浏览器。

我会建议在 Web Worker 的概念下做,因为它独立于其他脚本并且在不影响页面性能的情况下运行。

  1. 创建一个网络工作者 (demo_worker.js)

    var i = 0;
    var date = new Date();
    var counter = 10;
    var myFunction = function(){
        i = i + 1;
        clearInterval(interval);
        if(date.getHours() === 8 && date.getMinutes() === 0) {
            counter = 26280000;
            postMessage("hello"+i);
        }    
        interval = setInterval(myFunction, counter);
    }
    var interval = setInterval(myFunction, counter);
    
  2. 在 Ur 代码中使用 web worker,如下所示。

    var w;    
    function startWorker() {
        if (typeof(Worker) !== "undefined") {
            if (typeof(w) == "undefined") {
                w = new Worker("demo_worker.js");
                w.onmessage = function(event) {
                    window.print();
                };
            } else {
                document.getElementById("result").innerHTML = "Sorry, your browser does not support HTML5 Web Workers";
            }
        }
    }
    

我想它会帮助你。

我已经写了函数

  • 允许秒表达延迟,new Date()格式和stringnew Date格式
  • 允许取消计时器

这是代码:

"use strict"
/**
  This function postpones execution until given time.
  @delay might be number or string or `Date` object. If number, then it delay expressed in seconds; if string, then it is parsed with new Date() syntax. Example:
      scheduleAt(60, function() {console.log("executed"); }
      scheduleAt("Aug 27 2014 16:00:00", function() {console.log("executed"); }
      scheduleAt("Aug 27 2014 16:00:00 UTC", function() {console.log("executed"); }
  @code function to be executed
  @context @optional `this` in function `code` will evaluate to this object; by default it is `window` object; example:
      scheduleAt(1, function(console.log(this.a);}, {a: 42})
  @return function which can cancel timer. Example:
      var cancel=scheduleAt(60, function(console.log("executed.");});
      cancel();
      will never print to the console.
*/

function scheduleAt(delay, code, context) {

    //create this object only once for this function
    scheduleAt.conv = scheduleAt.conv || {
        'number': function numberInSecsToUnixTs(delay) {
            return (new Date().getTime() / 1000) + delay;
        },
        'string': function dateTimeStrToUnixTs(datetime) {
            return new Date(datetime).getTime() / 1000;
        },
        'object': function dateToUnixTs(date) {
            return date.getTime() / 1000;
        }
    };

    var delayInSec = scheduleAt.conv[typeof delay](delay) - (new Date().getTime() / 1000);

    if (delayInSec < 0) throw "Cannot execute in past";

    if (debug) console.log('executing in', delayInSec, new Date(new Date().getTime() + delayInSec * 1000))

    var id = setTimeout(
        code,
        delayInSec * 1000
    );

    //preserve as a private function variable setTimeout's id
    return (function(id) {
        return function() {
            clearTimeout(id);
        }
    })(id);
}

使用方法如下:

scheduleAt(2, function() {
    console.log("Hello, this function was delayed 2s.");
});

scheduleAt(
    new Date().toString().replace(/:\d{2} /, ':59 '),
    function() {
        console.log("Hello, this function was executed (almost) at the end of the minute.")
    }
);

scheduleAt(new Date(Date.UTC(2014, 9, 31)), function() {
    console.log('Saying in UTC time zone, we are just celebrating Helloween!');
})