web-dev-qa-db-fra.com

En JavaScript, comment puis-je exécuter une fonction à un moment précis?

J'ai un site Web qui héberge un tableau de bord: je peux modifier le JavaScript sur la page et je l'ai actuellement rafraîchissant toutes les cinq secondes.

J'essaie maintenant de faire fonctionner une window.print() tous les jours à 8 h.

Comment pourrais-je faire ça?

15
user3738622

JavaScript est pas l'outil pour cela. Si vous voulez que quelque chose s'exécute à une heure spécifique chaque jour, vous recherchez presque certainement quelque chose qui s'exécute localement, comme python ou applescript .


Cependant, considérons un instant que JavaScript est votre seule option. Il y a plusieurs façons de procéder, mais je vais vous donner le plus simple.

Tout d'abord, vous devrez créer une new Date() et définir un intervalle de vérification pour voir si l'heure est 8 (pour 8 heures du matin).

Cela vérifiera chaque minute (60000 millisecondes) pour voir s'il est huit heures:

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)

Il ne s'exécutera pas à exactement 8 heures (à moins que vous ne commenciez à l'exécuter à la minute) car il vérifie une fois par minute. Vous pouvez réduire l'intervalle autant que vous le souhaitez pour augmenter la précision de la vérification, mais c'est trop exagéré: il vérifiera toutes les minutes de toutes les heures de tous les jours pour voir si c'est 8 o 'l'horloge.

L'intensité de la vérification est due à la nature de JavaScript: il existe de bien meilleurs langages et frameworks pour ce genre de choses. Étant donné que JavaScript s'exécute sur les pages Web lorsque vous les chargez, il n'est pas destiné à gérer des tâches étendues et durables.

Sachez également que cela nécessite que la page Web sur laquelle elle est exécutée soit ouverte. Autrement dit, vous ne pouvez pas avoir une action planifiée se produisant tous les jours à 8 heures si la page n'est pas ouverte faisant le comptage et la vérification toutes les minutes .

Vous dites que vous rafraîchissez déjà la page toutes les cinq secondes: si c'est vrai, vous n'avez pas du tout besoin de la minuterie. Vérifiez chaque fois que vous actualisez la page:

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
}

Avec cela, vous devez également vérifier les secondes car vous actualisez toutes les cinq secondes, vous obtiendrez donc des tâches en double.


Cela dit, vous voudrez peut-être faire quelque chose comme this ou écrire un flux de travail Automator pour les tâches planifiées sur OS X.

Si vous avez besoin de quelque chose de plus indépendant de la plateforme, j'envisagerais sérieusement de jeter un œil à Python ou Bash .


En tant que mise à jour, JavaScript for Automation a été introduit avec OS X Yosemite, et il semble offrir un moyen viable d'utiliser JavaScript pour ce genre de chose (bien que vous ne l'utilisiez évidemment pas dans le même contexte ; Apple vous donne juste une interface pour utiliser un autre langage de script localement).

Si vous êtes sous OS X et que vous voulez vraiment utiliser JavaScript, je pense que c'est la voie à suivre.

Les notes de publication liées à ci-dessus semblent être la seule documentation existante à ce jour (qui est ~ 2 mois après la publication de Yosemite au public), mais elles valent la peine d'être lues. Vous pouvez également jeter un œil à la balise javascript-automation pour quelques exemples.

J'ai également trouvé le JXA Cookbook extrêmement utile.

Vous devrez peut-être modifier légèrement cette approche pour l'adapter à votre situation particulière, mais je vais donner un aperçu général.

  1. Créez une application vierge dans Automator.
    • Ouvrez Automator.app (il doit se trouver dans votre répertoire Applications) et créez un nouveau document.
    • Dans la boîte de dialogue, choisissez "Application". Automator new document dialog
  2. Ajoutez une action JavaScript.
    • L'étape suivante consiste à ajouter réellement le JavaScript qui sera exécuté. Pour ce faire, commencez par ajouter une action "Exécuter JavaScript" de la barre latérale au flux de travail. Drag the JS file into the workflow
  3. Écrivez le JavaScript.

    • C'est là que vous devrez savoir ce que vous voulez faire avant de continuer. D'après ce que vous avez fourni, je suppose que vous voulez exécuter window.print() sur une page chargée dans Safari. Vous pouvez le faire (ou, plus généralement, exécuter JS arbitraire dans un onglet Safari) avec ceci:

      var safari = Application('Safari');
      safari.doJavaScript('window.print();', { in: safari.windows[0].currentTab });
      
    • Vous devrez peut-être ajuster le windows auquel vous accédez en fonction de votre configuration.
  4. Enregistrez l'application.
    • Enregistrer (File -> Save Ou +S) le fichier en tant qu'application dans un emplacement que vous pouvez trouver (ou iCloud).
  5. Planifiez-le pour qu'il s'exécute.
    • Ouvrez le calendrier (ou iCal).
    • Créez un nouvel événement et donnez-lui un nom identifiable; ensuite, réglez l'heure à l'heure souhaitée (8 h 00 dans ce cas).
    • Réglez l'événement pour qu'il se répète quotidiennement (ou hebdomadairement, mensuellement, etc. - quelle que soit la fréquence à laquelle vous souhaitez qu'il se déroule).
    • Définissez l'alerte (ou l'alarme, selon votre version) sur personnalisée.
    • Choisissez "Ouvrir le fichier" et sélectionnez le fichier d'application que vous avez enregistré.
    • Choisissez "Au moment de l'événement" pour l'option de synchronisation des alertes. GIF instructions for scheduling the event

C'est tout! Le code JavaScript que vous avez écrit dans le fichier d'application s'exécutera chaque fois que cet événement est défini pour s'exécuter. Vous devriez pouvoir revenir à votre fichier dans Automator et modifier le code si nécessaire.

42
AstroCB
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);
    }
}

Pour l'utiliser:

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

Fondamentalement, obtenez l'horodatage d'aujourd'hui, l'horodatage d'aujourd'hui à 8 heures si exécuté à temps, ou demain à 8 heures, puis définissez un intervalle de 24h pour exécuter le code tous les jours. Vous pouvez facilement modifier l'heure de son exécution en définissant le début de la variable à un horodatage différent.

Je ne sais pas comment il sera utile de faire cette réflexion, comme d'autres l'ont souligné, vous devrez ouvrir la page toute la journée pour voir cela se produire ...

De plus, puisque vous rafraîchissez toutes les 5 secondes:

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();
    }
}

Exécutez-le de la même manière que toutes les 8 heures, il semble que 8 heures soit 2,5 secondes devant ou derrière, et exécutez-le si c'est le cas.

8
DrakaSAN

J'essaie de donner ma réponse en espérant que cela pourrait aider:

    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);
    }

Avec startJobAt, vous ne pouvez exécuter qu'une seule des tâches que vous souhaitez, mais si vous devez réexécuter votre tâche, c'est à vous de rappeler startJobAt.

au revoir

Ps

Si vous avez besoin d'une opération d'impression automatique, sans boîte de dialogue, pensez à utiliser http://jsprintsetup.mozdev.org/reference.html plugin pour mozilla ou autre plugin pour d'autres bowsers.

4
gaetanoM

J'ai écrit une fonction qui

  • permet d'exprimer le délai en secondes, le format new Date() et string's new Date format
  • permet d'annuler la minuterie

Voici le code:

"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);
}

Utilisez-le comme suit:

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!');
})
2
test30

Je proposerai de le faire dans le concept Web Worker, car il est indépendant des autres scripts et s'exécute sans affecter les performances de la page.

  1. Créer un travailleur Web (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. Utilisez le travailleur Web dans le code Ur comme suit.

    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";
            }
        }
    }
    

Je pense que cela vous aidera.

2
Pradeepta