Alsacreations.com - Actualités - Archives (mars 2023)

Les dernières actualités d'Alsacreations.com

Le: 21 03 2023 à 13:37 Auteur: Rodolphe

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.

Navigation Timing dans la console

Usage pour statistiques

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).

Publié par Alsacreations.com

Le: 14 03 2023 à 13:37 Auteur: Rodolphe

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.

Cas d'usage

On utilise des workers dans les cas suivants (et d'autres) pour éviter de bloquer l'interface :

  • Calculs complexes : Si vous avez besoin de calculer des valeurs complexe qui prennent du temps à s'exécuter, vous pouvez utiliser un web worker pour déléguer ces calculs à un processus en arrière-plan et éviter de bloquer l'interface utilisateur (UI) de l'application.
  • Traitement de données : Si vous avez besoin de traiter de grandes quantités de données qui prennent du temps à s'exécuter, vous pouvez utiliser un web worker pour déléguer ce traitement à un processus en arrière-plan et éviter de surcharger le processeur.
  • Téléchargement de fichiers : Si vous avez besoin de télécharger de gros fichiers qui prennent du temps, vous pouvez utiliser un web worker pour déléguer cette tâche.
  • Animations complexes : Si vous avez besoin d'animations complexes qui prennent du temps à s'exécuter, vous pouvez utiliser un web worker pour déléguer l'exécution de ces animations à un processus en arrière-plan et économiser les ressources.

Une démo vaut mille mots

⚗️ L'exemple le plus parlant peut être retrouvé en ligne : Sorting 50K Array with Bubble Sort.

Capture d'écran d'une démonstration de web worker

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.

Limitations

Par leur nature, les workers ont des limites.

  1. Ils ne peuvent pas accéder à certaines propriétés de l'objet 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.
  2. Ils ne peuvent pas afficher de fenêtres de dialogue ou des boîtes de message, car ils n'ont pas accès aux fonctionnalités de l'interface graphique de l'application.
  3. Ils ne peuvent pas utiliser certains objets de l'API navigation, comme history ou location, car ils n'ont pas accès à la barre d'adresse ou à l'historique de navigation de l'application.
  4. Ils ne peuvent pas interagir directement avec le DOM de la page, car ils n'ont pas accès aux éléments HTML de l'application. Pour mettre à jour le DOM depuis un web worker, vous devez en réalité envoyer un message au processus principal de l'application, qui lui même interviendra.
  5. Ils ne peuvent pas accéder à certaines APIs du navigateur, comme celles qui gèrent les cookies ou les notifications, car elles sont liées à l'interface de l'application, du document, du navigateur.

Initialisation d'un worker

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.

Exemple concret

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.

Publié par Alsacreations.com

Le: 07 03 2023 à 13:37 Auteur: Rodolphe

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.

Le logo de Deno en situation

Un kiwi s'est caché dans cette image, saurez-vous le retrouver ?

Quelles sont les différences ?

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 :

  • Deno a été conçu pour être plus sécurisé que Node.js : son noyau a été écrit en Rust, qui est réputé pour sa robustesse, alors que Node fut conçu en C++. Par ailleurs tous les fichiers et ressources externes sont bloqués par défaut, ce qui signifie que vous devez explicitement autoriser l'accès à ces fichiers et ressources avant de pouvoir y accéder dans votre code. Cela peut aider à prévenir les attaques de type "chemin d'accès transversal" qui sont courantes dans les applications.
  • Deno supporte nativement TypeScript et JavaScript (tandis que Node.js utilise JavaScript bien entendu). TypeScript est un sur-ensemble de JavaScript qui ajoute comme son nom le suggère le typage statique des données, ce qui peut aider à éviter certains types d'erreurs de programmation.
  • Deno met l'accent sur la simplicité et l'uniformité, ce qui se reflète dans sa conception générale : toutes les fonctionnalités sont accessibles à travers un seul module global, plutôt que d'être divisées en différents modules comme c'est le cas dans Node. De plus, Deno inclut toutes les bibliothèques et outils nécessaires à l'exécution de code, vous n'avez donc pas besoin d'installer des packages tiers comme c'est le cas avec Node et npm.
  • Deno souhaite être au plus proche des standards et API natives par exemple il embarque Fetch ou WebStorage... dont une compatibilité avec les navigateurs : avec des ES Modules il n'y a pas besoin de webpack pour que ce soit prêt à l'emploi.

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.

Comment utiliser Deno ?

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

Publié par Alsacreations.com