Les dernières actualités d'Alsacreations.com
Navigation Timing API est une interface de programmation qui permet d'accéder à des informations sur les performances de navigation d'un site Web, générées par le navigateur. Cela correspond à peu près aux informations que l'on trouve dans l'onglet Performance des devtools mais avec un accès "programmatique" plutôt que visuel. Ainsi on peut mesurer les temps de chargement et de rendu, non seulement sur son propre poste mais aussi sur celui des internautes et récupérer l'information. Différents événements sont monitorés et retournés en plus du temps de chargement total de la page. Le support est très bon sur tous les navigateurs depuis environ 2014.
â En réalité cette API profite d'un interface déjà décrite dans une autre spécification : Performance Timeline qui elle-même étend les pouvoirs déjà offerts par High Resolution Time.
Voici un exemple de code qui utilise l'API Navigation Timing pour mesurer le temps total :
// Récupération de l'objet de performance de navigation
const perf = window.performance;
// Récupération de l'événement de chargement de la page
const loadEvent = perf.timing.loadEventEnd;
// Récupération du temps actuel
const now = perf.now();
// Calcul du temps total de chargement (en millisecondes)
const pageLoadTime = now - loadEvent;
// Affichage du temps total de chargement de la page
console.log("Temps total de chargement : " + pageLoadTime + " ms");
Ici on se concentre sur loadEventEnd
mais il existe bien d'autres propriété intéressantes spécifiques à cette API :
startTime
: temps (en ms) auquel la navigation a commencé, c'est-à-dire lorsque l'internaute a cliqué sur un lien ou saisi une URL dans la barre d'adresse.loadEventStart
et loadEventEnd
: temps (en ms) auquel l'événement load
de la page a été déclenché et s'est terminé.domInteractive
: temps (en ms) auquel le navigateur a terminé le parsing du document HTML et a commencé à traiter les scripts et les ressources externes de la page.domContentLoadedEventStart
et domContentLoadedEventEnd
: temps (en ms) auxquels le navigateur a démarré puis terminé le chargement de la partie "non-bloquante" de la page (c'est-à-dire les éléments qui ne sont pas nécessaires au chargement initial de la page, comme les images et les scripts en mode asynchrone).domComplete
: temps (en ms) auquel le navigateur a terminé le chargement de tous les éléments de la page, y compris les ressources bloquantes (comme les scripts JavaScript qui doivent être chargés et exécutés avant que la page soit rendue).Et des propriété héritées des interfaces déjà mentionnées dans d'autres API :
redirectStart
et redirectEnd
: temps (en ms) auquel la redirection a commencé et s'est terminée, si la navigation a été redirigée vers une autre URL.fetchStart
: temps (en ms) auquel la requête HTTP a été envoyée pour récupérer le document HTML de la page.domainLookupStart
et domainLookupEnd
: temps (en ms) auquel la résolution de nom de domaine a commencé et s'est terminée.connectStart
et connectEnd
: temps (en ms) auquel la connexion au serveur a commencé et s'est terminée.requestStart
: temps (en ms) auquel la requête HTTP pour le document HTML de la page a été envoyée au serveur.responseStart
et responseEnd
: temps (en ms) auquel la réponse du serveur a été reçue et la réception du document HTML de la page a été terminée.domLoading
: temps (en ms) auquel le navigateur a commencé à parser le document HTML de la page.À noter que certaines clés sont préservées pour raisons de compatibilité avec la version 1 de l'API mais dépréciées dans la dernière à jour.
Ces propriétés associées ensemble peuvent être utilisées pour mesurer différentes étapes du processus de chargement et identifier les goulots d'étranglement à améliorer.
Vous pouvez également examiner tout ceci en entrant window.performance.timing
dans la Console du navigateur.
Voici un exemple de code qui utilise la Navigation Timing API pour mesurer le temps total de chargement d'une page Web et envoyer cette information à une API de statistiques :
// Récupération de l'objet de performance de navigation
const perf = window.performance;
// Récupération de l'événement de chargement de la page
const loadEvent = perf.timing.loadEventEnd;
// Récupération du timing actuel
const now = perf.now();
// Calcul du temps total de chargement (en millisecondes)
const pageLoadTime = now - loadEvent;
// préparation de l'objet à envoyer à l'API de statistiques
const statsData = {
pageLoadTime: pageLoadTime
};
// envoi des données à l'API de statistiques sous forme JSON
fetch("https://example.com/stats", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(statsData)
})
.then(function(response) {
console.log("Données envoyées à l'API de statistiques :", response);
})
.catch(function(error) {
console.error("Erreur lors de l'envoi des données à l'API de statistiques :", error);
});
Notez que cet exemple est simplifié et ne prend pas en compte tous les cas possibles par exemple, si la requête à l'API de statistiques échoue (dans ce cas il faudrait traiter l'erreur renvoyée) ou si la page est redirigée avant que les données puissent être envoyées (dans ce cas il faut décider si on ignore ou si on stocke l'information temporairement dans sessionStorage pour tenter un nouvel envoi sur une page suivante).
Les web workers sont des threads JavaScript qui permettent de déléguer des tâches longues et/ou intensives en CPU à des processus en arrière-plan, afin d'éviter de bloquer l'interface de l'application web.
Cela signifie que vous pouvez exécuter du code JavaScript qui prend du temps à s'exécuter, comme des calculs complexes, des opérations de traitement de données ou des téléchargements de fichiers, sans perturber la réactivité de votre application et notamment déclencher l'apparition d'un avertissement du navigateur de type Attention : le script ne répond pas, voulez-vous attendre ou l'arrêter ?
.
Le support de cette technique est très bon de nos jours avec tous les navigateurs majeurs desktop et mobiles, depuis IE10 inclus et Android 4.4, soit depuis environ 2014. Reportez-vous au tableau Caniuse : Web Workers pour tous les détails.
Pour utiliser un web worker, vous devez créer un fichier JavaScript séparé qui contiendra le code à exécuter en arrière-plan, puis utiliser l'API des web workers pour instancier un web worker à partir de ce fichier et lui envoyer des messages pour lancer des tâches ou obtenir des résultats. Le web worker exécutera le code de manière asynchrone, de sorte que vous pouvez continuer à interagir avec l'application pendant que le code du web worker s'exécute en arrière-plan.
On utilise des workers dans les cas suivants (et d'autres) pour éviter de bloquer l'interface :
âï¸ L'exemple le plus parlant peut être retrouvé en ligne : Sorting 50K Array with Bubble Sort.
Il s'agit d'effectuer un tri sur un tableau par algorithme bubble sort (tri à bulles) avec 2 méthodes : - sans worker : de manière classique, cet exercice bloque l'interface, on peut le voir aux styles figés du bouton, à l'absence de l'animation de la barre de progression, et de réactivité globale. - avec worker : le document principal continue de vivre avec ses états, animations, interactions, sans bloquer durant la réalisation du calcul.
Par leur nature, les workers ont des limites.
window
, comme window.document
, car ils sont exécutés dans un contexte de thread séparé et ne partagent pas le même espace de nomage que le code principal de l'application. Cela également pour éviter des conflits d'accès aux ressources avec les scripts de la page principale.history
ou location
, car ils n'ont pas accès à la barre d'adresse ou à l'historique de navigation de l'application.Créez un fichier JavaScript séparé qui contiendra le code à exécuter en arrière-plan. Ce fichier sera appelé "fichier de travail".
Dans votre code principal, utilisez le constructeur Worker()
de l'objet Worker pour instancier un web worker à partir du fichier de travail. Cette méthode prend en paramètre le chemin vers le fichier :
const worker = new Worker('path/to/worker.js');
Vous pouvez maintenant envoyer des messages au web worker en utilisant la méthode postMessage()
de l'objet Worker, et par la même occasion lancer les opérations :
worker.postMessage({ message: 'Hello, worker!' });
Vous pouvez également définir un gestionnaire d'événements qui sera appelé chaque fois que le web worker envoie un message au code principal en utilisant la méthode addEventListener()
de l'objet Worker :
worker.addEventListener('message', (event) => {
console.log(event.data);
});
Lorsque vous avez fini de travailler avec le web worker, vous pouvez le fermer en utilisant la méthode terminate()
:
worker.terminate();
Vous pouvez également utiliser l'API des web workers pour gérer les erreurs et les exceptions qui se produisent dans le code du web worker en définissant des gestionnaires d'événements pour les événements error
et messageerror
.
Rappelez-vous que le code du fichier de travail est exécuté dans un contexte de thread séparé, de sorte que toutes les variables et fonctions définies dans le fichier de travail ne seront pas disponibles dans le code principal de l'application. Pour communiquer entre le code principal et le web worker, vous devez utiliser l'API des web workers pour envoyer et recevoir des messages.
Voici un exemple basique mais concret d'utilisation d'un web worker pour effectuer des calculs. Attention les instructions sont présentées de manière minimaliste, il serait plus propre de les réunir dans un objet, une classe, etc. pour ne pas manipuler des variables globales.
On crée un fichier JavaScript séparé qui contiendra le code à exécuter en arrière-plan. Par exemple, le fichier de travail pourrait ressembler à ceci :
// La fonction de calcul complexe
function calculate(data) {
// Effectuez les calculs complexes ici
const result = /* résultat des calculs */;
postMessage(result);
}
// Attendez un message du code principal
onmessage = function(e) {
// Appelez la fonction de calcul avec les données reçues
calculate(e.data);
};
Dans votre code principal, utilisez la méthode Worker()
pour instancier un web worker à partir du fichier de travail :
const worker = new Worker('worker.js');
Définissez un gestionnaire d'événements qui sera appelé chaque fois que le web worker envoie un message au code principal en utilisant la méthode addEventListener() de l'objet Worker :
worker.addEventListener('message', (event) => {
console.log(event.data); // Affiche le résultat des calculs
});
Envoyez un message au web worker en utilisant la méthode postMessage() de l'objet Worker et en lui envoyant les données à traiter :
worker.postMessage({ data: /* données à traiter */ });
Le web worker recevra le message et exécutera la fonction de calcul en arrière-plan, en utilisant les données envoyées par le code principal. Lorsque les calculs sont terminés, le web worker enverra un message au code principal avec le résultat, qui sera affiché dans le gestionnaire d'événements défini.
Deno est un environnement d'exécution JavaScript et TypeScript qui a été pensé et conçu pour être une alternative à Node.js. Il permet à ce titre d'exécuter du code JavaScript, en-dehors d'un navigateur c'est-à-dire en ligne de commande ou en mode serveur grâce au moteur V8 de Chromium... mais il a été construit avec une série de différences clés par rapport à Node.js.
Deno a été lancé par le créateur de Node lui-même : Ryan Dahl. Lors d'une conférence JSConf, ce dernier avait exprimé des regrets relatifs à sa première oeuvre qui date (déjà) de 2009. Vous pouvez découvrir ses arguments en vidéo : 10 choses que je regrette à propos de Node.js - Ryan Dahl
Entre autres :
L'import de paquets se fait via URL, ce qui peut sembler initialement étrange mais fait sens dans la philosophie de Deno qui se veut décentralisé. Ce concept est bien expliqué par la documentation : Linking to third party code. Fini node_modules et package.json.
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
Côté performance, les résultats sont relativement similaires entre Deno et Node car le moteur interne reste V8.
Avant toute chose, il faut garder à l'esprit que Deno est bien plus récent et que si des gros progrès sont réalisés pour améliorer la stabilité, on manque encore certainement de recul, de retours de bugs, de documentation et d'une communauté aussi importante que celle de Node pour déclarer que l'un peut remplacer l'autre d'un claquement de doigts... même s'il prévoit un module de compatibilité avec Node.
Pour utiliser Deno, vous devez d'abord l'installer en suivant les instructions fournies sur le site web officiel de Deno. Vous pouvez ensuite lancer des exécutions de code avec la commande deno
dans le terminal, et vous vous retrouverez avec un environnement habituel où l'on peut entrer des instructions JavaScript et quitter avec close()
.
Voici un exemple de script Deno simple qui affiche "Hello World" dans la console :
// Fichier hello.js ou hello.ts
console.log("Hello World!");
Pour exécuter ce programme, vous pouvez utiliser la commande deno run
:
deno run hello.js
Dès que l'on va tenter d'accéder à des ressources, Deno va demander l'autorisation. Par exemple pour l'accès en écriture à un fichier :
â ï¸ Deno requests write access to "hello.log". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]
ou au réseau avec fetch :
â ï¸ Deno requests net access to "wikipedia.org". Run again with --allow-net to bypass this prompt. Allow? [y/n (y = yes allow, n = no deny)]
On va pouvoir débloquer ces autorisations avec --allow-write
(écriture de fichiers), --allow-net
(accès au réseau), --allow-env
accès à l'environnemment et --allow-run
pour exécuter des sous-processus.
Il existe de nombreuses autres commandes et options que vous pouvez utiliser avec Deno pour exécuter et gérer vos programmes. Pour en savoir plus, consultez la documentation officielle de Deno