Vanilla JavaScript Timer

Voici un minuteur simple et optimisé qui peut être utilisé sur n'importe quel projet de site Internet : j'expose simplement la logique et explique en détail son fonctionnement.

Le code du minuteur JavaScript est complètement autonome (aucune dépendance à des librairies) et fonctionne sur tous les navigateurs qui supportent ECMAScript 3+ (ES3, 1999).

Le code peut aisément être adapté à toute librairie à des fins d'optimisation et d'uniformisation. Le poids du fichier est négligeable et varie entre 500 octets et 2 ko selon la technique de minimisation.

Code source

/*
* La fonction « TimerEngine » sera instanciée, on peut
* donc la considérer comme une classe (OOP).
*
* Ex: var myTimer=new TimerEngine(...);
* Voir le bloc « utilisation » après le code source du minuteur.
*/
 
function TimerEngine(end_date,callback){
/*
* end_date:date
* callback:function
*/
 
// On s'assure que le paramètre « end_date » est bien un objet Date.
var _end_date=Object.prototype.toString.call(end_date)==='[object Date]'?end_date:new Date();
 
// On s'assure que le paramètre « callback » est bien une fonction.
var _callback=Object.prototype.toString.call(callback)==='[object Function]'?callback:null;
 
/*
* On assigne la portée de l'instance à une variable afin de l'utiliser
* lors des appels de fonction publique interne. (Il est possible que la 
* portée d'une fonction publique soit modifiée selon le contexte d'exécution
* et nous voulons simplement éviter ce type d'erreur)
*/
var _scope=this;
 
/*
* On définit l'intervalle de temps entre chaque exécution (millisecondes).
* Puisqu'on calcule le temps écoulé, modifier cette valeur
* n'affecte que la fréquence du calcul et la précision du rendu.
*/
var _interval=1000;
 
// on définit une variable qui sera la référence à l'intervalle afin de pouvoir l'arrêter
var _interval_id;
 
/*
* Une fonction privée à la classe qui sert à ajouter des zéros
* afin d'uniformiser les nombres lors de l'affichage.
*/
function pad(input,limit){
/*
* input:number
* limit:number
*/
 
// On transforme le paramètre « input » en chaîne de caractères
var input=input+'';
 
// On s'assure que le paramètre « limit » est bien un nombre
var limit=typeof limit=='number'?limit:1;
 
/*
* Si la chaîne de caractères est de la bonne longueur, on la retourne.
* Sinon, on créer un tableau de la longueur désirée, puis on ajoute 
* des zéros entre les éléments du tableau lors de la conversion
* en chaîne de caractères.
*/
return input.length>=limit?input:new Array(limit-input.length+1).join('0')+input;
}
 
/*
* Une fonction privée à la classe qui sert à calculer le temps écoulé. Les
* résultats sont envoyés à la fonction « callback », externe à la classe, utilisée
* pour gérer le rendu HTML.
*/
function calculate(){
 
/*
* On calcule la différence de temps, en millisecondes, entre
* la date initiale et le temps présent.
*/
var difference=_end_date.getTime()-new Date().getTime();
 
/*
* On créer un objet « data » afin de structurer nos données puis on
* convertit les millisecondes en différentes unités de temps selon
* le schéma suivant:
*  num: le nombre calculé
*  pad: le nombre calculé uniformisé avec le nombre de zéros désiré
*/
var data={
days:{
num:difference/(1000*60*60*24),
pad:0
},
hours:{
num:(difference/(1000*60*60))%24,
pad:0
},
minutes:{
num:((difference/1000)/60)%60,
pad:0
},
seconds:{
num:(difference/1000)%60,
pad:0
}
}
 
/*
* Afin de minimiser le code, on créer une boucle
* pour formater les données de l'objet.
*/
for(var i in data){
 
/*
* La variable « num » peut contenir plusieurs nombres dans la partie
* décimale, nous allons donc l'arrondir à l'entier inférieur.
*  Ex: 1.9999072800925926 = 1
* On s'assure également que le chiffre soit toujours supérieur ou égal à 0
*/
data[i].num=Math.max(Math.floor(data[i].num),0);
 
/*
* La chaîne de caractères « pad » est simplement le chiffre calculé
* et arrondi « num » mais uniformisé avec le nombre de zéros désiré.
*/
data[i].pad=pad(data[i].num,2);
}
 
/*
* On créer un booléen qui aura un état « vrai » si tout
* les valeurs « num » sont à zéro, ce qui indique que le 
* minuteur est terminé.
*/
data.completed=data.days.num==0&&data.hours.num==0&&data.minutes.num==0&&data.seconds.num==0;
 
/*
* Si la fonction « callback » est définie, on fait un appel
* en passant l'objet « data » en paramètre.
*/
if(_callback!=null)void _callback(data);
 
/*
* Si le minuteur est terminé, on arrête les
* exécutions ultérieures de la fonction « calculate »
* pour limiter l'utilisation des ressources de l'appareil.
*/
if(data.completed)void _scope.stop();
};
 
// Une fonction publique qui sert à démarrer le minuteur 
this.start=function(){
// On appelle la fonction « stop » afin de réinitialiser le minuteur.
void _scope.stop();
 
/*
* On créer un intervalle d'exécution et assigne
>* l'identifiant généré à la variable.
*/
_interval_id=setInterval(calculate,_interval);
 
/*
* Puisque l'intervalle de calcul est de 1 seconde, on appelle
* la fonction « calculate » pour exécuter le premier rendu
* afin qu'il n'y ait pas de délai.
*/
void calculate();
};
 
// Une fonction publique qui sert à arrêter le minuteur 
this.stop=function(){
void clearInterval(_interval_id);
};
 
};
 

Utilisation

/*
* On instancie la classe TimerEngine et assigne
* l'instance à la variable « myTimer ».
* 
* On change la date de fin selon nos besoins.
*  new Date(années,mois,jours,heures,minutes,secondes)
* 
* C'est dans la fonction anonyme que sera gérée la vue
* du minuteur et on est libre de l'adapter selon nos
* goûts et besoins du projet.
* 
*/
var myTimer=new TimerEngine(
new Date(2025,2,20,23,0,0),
function(data){
// data:object
 
// On sélectionne l'élément ayant l'identifiant « demo ».
var element=document.getElementById('demo');
 
if(element!=null){
// On prépare puis on change le contenu de l'élément.
var content='';
content+='<span class="d">'+data.days.pad+'</span>';
content+='<span class="h">'+data.hours.pad+'</span>';
content+='<span class="m">'+data.minutes.pad+'</span>';
content+='<span class="s">'+data.seconds.pad+'</span>';
element.innerHTML=content;
}
 
/*
* Lorsque le minuteur est terminé, le booléen « data.completed » aura
* la valeur « vrai ». On peut donc démarrer une animation, changer
* le style, afficher un message, etc.
* 
* À noter que le minuteur est déjà arrêté lorsque cette condition
* devient « vrai » donc, nul besoin de faire un appel à la
* fonction « myTimer.stop(); ».
*/
if(data.completed){
// le décompte est terminé
}
 
}
);
 
/*
* On démarre le minuteur.
*/
void myTimer.start();
//void myTimer.stop();
 

Sur les médias sociaux : Instagram, YouTube et Twitter.