Lorsque vous entendez l'expression « Stockage local asynchrone », qu'est-ce qui vous vient à l'esprit ? Au début, vous pourriez penser qu’il s’agit d’une implémentation magique du stockage local basé sur un navigateur. Cependant, cette hypothèse est incorrecte. Le stockage local asynchrone n'est ni lié au navigateur ni un mécanisme de stockage typique. Il est probable qu'une ou deux bibliothèques que vous avez utilisées l'utilisent sous le capot. Dans de nombreux cas, cette fonctionnalité peut vous éviter de gérer un code compliqué.
Qu’est-ce que le stockage local asynchrone ?
Async Local Storage est une fonctionnalité introduite dans Node.js, initialement ajoutée dans les versions v13.10.0 et v12.17.0, puis stabilisée dans la v16.4.0. Il fait partie du module async_hooks, qui fournit un moyen de suivre les ressources asynchrones dans les applications Node.js. La fonctionnalité permet la création d'un contexte partagé auquel plusieurs fonctions asynchrones peuvent accéder sans le transmettre explicitement. Le contexte est disponible dans chaque (et unique) opération exécutée dans le rappel transmis à la méthode run() de l'instance AsyncLocalStorage.
Un modèle pour utiliser AsyncLocalStorage
Avant de plonger dans les exemples, expliquons le modèle que nous allons utiliser.
Initialisation
import { AsyncLocalStorage } from "async_hooks"; import { Context } from "./types"; export const asyncLocalStorage = new AsyncLocalStorage<context>(); // export const authAsyncLocalStorage = new AuthAsyncLocalStorage<authcontext>() </authcontext></context>
Dans le module ci-dessus, nous initialisons une instance de AsyncLocalStorage et l'exportons sous forme de variable.
Utilisation
asyncLocalStorage.run({ userId }, async () => { const usersData: UserData = await collectUsersData(); console.log("usersData", usersData); }); // (method) AsyncLocalStorage<unknown>.run<promise>>(store: unknown, callback: () => Promise<void>): Promise<void> (+1 overload) </void></void></promise></unknown>
La méthode run() prend deux arguments : storage, qui contient les données que nous souhaitons partager, et callback, où nous plaçons notre logique. En conséquence, le stockage devient accessible à chaque appel de fonction dans le rappel, permettant un partage transparent des données entre les opérations asynchrones.
async function collectUsersData() { const context = asyncLocalStorage.getStore(); }
Pour accéder au contexte, nous importons notre instance et appelons la méthode asyncLocalStorage.getStore(). Ce qui est bien, c'est que le stockage récupéré depuis getStore() est typé car nous avons transmis le type Context à AsyncLocalStorage lors de l'initialisation : new AsyncLocalStorage
Stockage local asynchrone comme contexte d'authentification
Il n'y a pas d'application web sans système d'authentification. Nous devons valider les jetons d'authentification et extraire les informations utilisateur. Une fois que nous avons obtenu l'identité de l'utilisateur, nous souhaitons la rendre disponible dans les gestionnaires de routes et éviter de dupliquer le code dans chacun d'eux. Voyons comment nous pouvons utiliser AsyncLocalStorage pour implémenter un contexte d'authentification tout en gardant notre code propre.
J'ai choisi fastify pour cet exemple.
Selon la documentation, fastify est :
Framework Web rapide et faible, pour Node.js
Ok, commençons :
- Installer fastify :
import { AsyncLocalStorage } from "async_hooks"; import { Context } from "./types"; export const asyncLocalStorage = new AsyncLocalStorage<context>(); // export const authAsyncLocalStorage = new AuthAsyncLocalStorage<authcontext>() </authcontext></context>
- Définir le type pour notre contexte d'authentification :
asyncLocalStorage.run({ userId }, async () => { const usersData: UserData = await collectUsersData(); console.log("usersData", usersData); }); // (method) AsyncLocalStorage<unknown>.run<promise>>(store: unknown, callback: () => Promise<void>): Promise<void> (+1 overload) </void></void></promise></unknown>
- Initialisez une instance de AsyncLocalStorage, attribuez-la à une variable et exportez la variable. N'oubliez pas de transmettre le type approprié : new AsyncLocalStorage
().
async function collectUsersData() { const context = asyncLocalStorage.getStore(); }
- Initialisez une instance Fastify et ajoutez un utilitaire de gestion des erreurs :
npm install fastify
Vient maintenant la partie très importante. Nous allons ajouter un hook onRequest pour envelopper les gestionnaires avec la méthode authAsyncLocalStorage.run().
type Context = Map;
Après une validation réussie, nous appelons la méthode run() depuis notre authAsyncLocalStorage. Comme argument de stockage, nous transmettons le contexte d'authentification avec l'ID utilisateur récupéré du jeton. Dans le rappel, nous appelons la fonction done pour continuer le cycle de vie Fastify.
Si nous avons des contrôles d'authentification qui nécessitent des opérations asynchrones, nous devons les ajouter au rappel. En effet, selon la documentation :
le rappel terminé n'est pas disponible lors de l'utilisation de async/await ou du renvoi d'une promesse. Si vous invoquez un rappel effectué dans cette situation, un comportement inattendu peut se produire, par ex. appel en double des gestionnaires
Voici un exemple de ce à quoi cela pourrait ressembler :
import { AsyncLocalStorage } from "async_hooks"; import { Context } from "./types"; export const authAsyncLocalStorage = new AsyncLocalStorage<context>(); </context>
Notre exemple ne comporte qu'un seul itinéraire protégé. Dans des scénarios plus complexes, vous devrez peut-être encapsuler uniquement des routes spécifiques avec le contexte d'authentification. Dans de tels cas, vous pouvez soit :
- Enveloppez le hook onRequest dans un plugin personnalisé qui s'applique uniquement à des routes spécifiques.
- Ajoutez une logique de distinction de route dans le hook onRequest lui-même.
Très bien, notre contexte est posé et nous pouvons désormais définir un itinéraire protégé :
import Fastify from "fastify"; /* other code... */ const app = Fastify(); function sendUnauthorized(reply: FastifyReply, message: string) { reply.code(401).send({ error: `Unauthorized: ${message}` }); } /* other code... */
Le code est assez simple. Nous importons authAsyncLocalStorage, récupérons l'userId, initialisons UserRepository et récupérons les données. Cette approche permet au gestionnaire d'itinéraire de rester propre et concentré.
Explorer comment Next.js utilise le stockage local asynchrone
Dans cet exemple, nous allons réimplémenter l'assistant de cookies de Next.js. Mais attendez, c'est un article sur AsyncLocalStorage, n'est-ce pas ? Alors pourquoi parle-t-on de cookies ? La réponse est simple : Next.js utilise AsyncLocalStorage pour gérer les cookies sur le serveur. C'est pourquoi lire un cookie dans un composant serveur est aussi simple que :
import Fastify from "fastify"; import { authAsyncLocalStorage } from "./context"; import { getUserIdFromToken, validateToken } from "./utils"; /* other code... */ app.addHook( "onRequest", (request: FastifyRequest, reply: FastifyReply, done: () => void) => { const accessToken = request.headers.authorization?.split(" ")[1]; const isTokenValid = validateToken(accessToken); if (!isTokenValid) { sendUnauthorized(reply, "Access token is invalid"); } const userId = accessToken ? getUserIdFromToken(accessToken) : null; if (!userId) { sendUnauthorized(reply, "Invalid or expired token"); } authAsyncLocalStorage.run(new Map([["userId", userId]]), async () => { await new Promise((resolve) => setTimeout(resolve, 2000)); sendUnauthorized(reply, "Invalid or expired token"); done(); }); }, ); /* other code... */
Nous utilisons la fonction cookies exportée depuis next/headers, qui propose plusieurs méthodes de gestion des cookies. Mais comment est-ce techniquement possible ?
Il est maintenant temps de commencer notre réimplémentation"
Tout d'abord, je tiens à mentionner que cet exemple est basé sur les connaissances que j'ai acquises grâce à une superbe vidéo, de Lee Robinson et en plongeant dans le référentiel Next.js.
Dans cet exemple, nous utiliserons Hono comme framework de serveur. Je l'ai choisi pour deux raisons :
- Je voulais juste essayer.
- Il offre un support solide pour JSX.
Première installation de Hono :
import { AsyncLocalStorage } from "async_hooks"; import { Context } from "./types"; export const asyncLocalStorage = new AsyncLocalStorage<context>(); // export const authAsyncLocalStorage = new AuthAsyncLocalStorage<authcontext>() </authcontext></context>
Maintenant, initialisez Hono et ajoutez un middleware :
asyncLocalStorage.run({ userId }, async () => { const usersData: UserData = await collectUsersData(); console.log("usersData", usersData); }); // (method) AsyncLocalStorage<unknown>.run<promise>>(store: unknown, callback: () => Promise<void>): Promise<void> (+1 overload) </void></void></promise></unknown>
Le code ressemble au middleware de l'exemple Fastify, n'est-ce pas ? Pour définir le contexte, nous utilisons setCookieContext, qui est importé du module cookies - notre implémentation simple et personnalisée de la fonction cookies. Suivons la fonction setCookieContext et naviguons jusqu'au module à partir duquel elle a été importée :
async function collectUsersData() { const context = asyncLocalStorage.getStore(); }
La fonction setCookieContext (dont nous avons transmis la valeur de retour à cookieAsyncLocalStorage.run() dans le middleware Hono) extrait les cookies du paramètre c, qui représente le contexte hono, et les regroupe avec des fermetures qui fournissent des fonctions utilitaires pour gérer les cookies.
Notre fonction cookies reproduit la fonctionnalité des cookies de next/headers. Il utilise la méthode cookieAsyncLocalStorage.getStore() pour accéder au même contexte qui est transmis à cookieAsyncLocalStorage.run() lorsqu'il est appelé.
Nous avons enveloppé le retour de notre fonction cookies dans une promesse d'imiter le comportement de l'implémentation Next.js. Avant la version 15, cette fonction était synchrone. Désormais, dans le code Next.js actuel, les méthodes renvoyées par les cookies sont attachées à un objet de promesse, comme le montre l'exemple simplifié suivant :
npm install fastify
Un autre point à mentionner est que dans notre cas, l'utilisation de cookies.setCookie et cookies.deleteCookie génère toujours une erreur, similaire au comportement observé dans Next.js lors de la définition de cookies dans un composant serveur. Nous avons codé en dur cette logique car, dans l'implémentation d'origine, la possibilité d'utiliser setCookie ou deleteCookie dépend de la propriété phase(WorkUnitPhase) stockée dans le stockage appelé RequestStore (il s'agit de l'implémentation d'AsyncLocalStorage et stocke également les cookies). Cependant, ce sujet conviendrait mieux à un autre article. Pour garder cet exemple simple, omettons la simulation de WorkUnitPhase.
Nous devons maintenant ajouter notre code React.
- Ajoutez le composant App :
type Context = Map;
- Ajouter un composant de gestion des cookies :
import { AsyncLocalStorage } from "async_hooks"; import { Context } from "./types"; export const authAsyncLocalStorage = new AsyncLocalStorage<context>(); </context>
L'utilisation des cookies est similaire à celle utilisée dans les composants du serveur Next.js React.
- Ajoutez un gestionnaire de route pour afficher le modèle :
import Fastify from "fastify"; /* other code... */ const app = Fastify(); function sendUnauthorized(reply: FastifyReply, message: string) { reply.code(401).send({ error: `Unauthorized: ${message}` }); } /* other code... */
Notre modèle est rendu par la méthode html à partir du contexte hono. Le point clé ici est que le gestionnaire de route s'exécute dans la méthode asyncLocalStorage.run(), qui prend cookieContext. De ce fait, nous pouvons accéder à ce contexte dans le composant DisplayCookies via la fonction cookies.
Il n'est pas possible de définir des cookies dans les composants du serveur React, nous devons donc le faire manuellement :
Actualisons une page :
Et voilà, nos cookies sont récupérés et affichés avec succès.
Conclusions
Il existe de nombreux autres cas d'utilisation pour asyncLocalStorage. Cette fonctionnalité vous permet de créer des contextes personnalisés dans presque n'importe quelle infrastructure de serveur. Le contexte asyncLocalStorage est encapsulé dans l'exécution de la méthode run(), ce qui facilite sa gestion. Il est parfait pour gérer des scénarios basés sur des requêtes. L'API est simple et flexible, permettant l'évolutivité en créant des instances pour chaque état. Il est possible de gérer de manière transparente des contextes séparés pour des éléments tels que l'authentification, la journalisation et les indicateurs de fonctionnalités.
Malgré ses avantages, il y a quelques considérations à garder à l’esprit. J'ai entendu des opinions selon lesquelles asyncLocalStorage introduit trop de « magie » dans le code. J'avoue que lorsque j'ai utilisé cette fonctionnalité pour la première fois, il m'a fallu un certain temps pour bien comprendre le concept. Une autre chose à considérer est que l’importation du contexte dans un module crée une nouvelle dépendance que vous devrez gérer. Cependant, en fin de compte, transmettre des valeurs via des appels de fonctions profondément imbriqués est bien pire.
Merci d'avoir lu et à bientôt dans le prochain post !?
PS : Vous pouvez retrouver les exemples (plus un bonus) ici
Source du message Bog : https://www.aboutjs.dev/en/async-local-storage-is-here-to-help-you
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Python convient plus aux débutants, avec une courbe d'apprentissage en douceur et une syntaxe concise; JavaScript convient au développement frontal, avec une courbe d'apprentissage abrupte et une syntaxe flexible. 1. La syntaxe Python est intuitive et adaptée à la science des données et au développement back-end. 2. JavaScript est flexible et largement utilisé dans la programmation frontale et côté serveur.

Python et JavaScript ont leurs propres avantages et inconvénients en termes de communauté, de bibliothèques et de ressources. 1) La communauté Python est amicale et adaptée aux débutants, mais les ressources de développement frontal ne sont pas aussi riches que JavaScript. 2) Python est puissant dans les bibliothèques de science des données et d'apprentissage automatique, tandis que JavaScript est meilleur dans les bibliothèques et les cadres de développement frontaux. 3) Les deux ont des ressources d'apprentissage riches, mais Python convient pour commencer par des documents officiels, tandis que JavaScript est meilleur avec MDNWEBDOCS. Le choix doit être basé sur les besoins du projet et les intérêts personnels.

Le passage de C / C à JavaScript nécessite de s'adapter à la frappe dynamique, à la collecte des ordures et à la programmation asynchrone. 1) C / C est un langage dactylographié statiquement qui nécessite une gestion manuelle de la mémoire, tandis que JavaScript est dynamiquement typé et que la collecte des déchets est automatiquement traitée. 2) C / C doit être compilé en code machine, tandis que JavaScript est une langue interprétée. 3) JavaScript introduit des concepts tels que les fermetures, les chaînes de prototypes et la promesse, ce qui améliore la flexibilité et les capacités de programmation asynchrones.

Différents moteurs JavaScript ont des effets différents lors de l'analyse et de l'exécution du code JavaScript, car les principes d'implémentation et les stratégies d'optimisation de chaque moteur diffèrent. 1. Analyse lexicale: convertir le code source en unité lexicale. 2. Analyse de la grammaire: générer un arbre de syntaxe abstrait. 3. Optimisation et compilation: générer du code machine via le compilateur JIT. 4. Exécuter: Exécutez le code machine. Le moteur V8 optimise grâce à une compilation instantanée et à une classe cachée, SpiderMonkey utilise un système d'inférence de type, résultant en différentes performances de performances sur le même code.

Les applications de JavaScript dans le monde réel incluent la programmation côté serveur, le développement des applications mobiles et le contrôle de l'Internet des objets: 1. La programmation côté serveur est réalisée via Node.js, adaptée au traitement de demande élevé simultané. 2. Le développement d'applications mobiles est effectué par le reactnatif et prend en charge le déploiement multiplateforme. 3. Utilisé pour le contrôle des périphériques IoT via la bibliothèque Johnny-Five, adapté à l'interaction matérielle.

J'ai construit une application SAAS multi-locataire fonctionnelle (une application EdTech) avec votre outil technologique quotidien et vous pouvez faire de même. Premièrement, qu'est-ce qu'une application SaaS multi-locataire? Les applications saas multi-locataires vous permettent de servir plusieurs clients à partir d'un chant

Cet article démontre l'intégration frontale avec un backend sécurisé par permis, construisant une application fonctionnelle EdTech SaaS en utilisant Next.js. Le frontend récupère les autorisations des utilisateurs pour contrôler la visibilité de l'interface utilisateur et garantit que les demandes d'API adhèrent à la base de rôles

JavaScript est le langage central du développement Web moderne et est largement utilisé pour sa diversité et sa flexibilité. 1) Développement frontal: construire des pages Web dynamiques et des applications à une seule page via les opérations DOM et les cadres modernes (tels que React, Vue.js, Angular). 2) Développement côté serveur: Node.js utilise un modèle d'E / S non bloquant pour gérer une concurrence élevée et des applications en temps réel. 3) Développement des applications mobiles et de bureau: le développement de la plate-forme multiplateuse est réalisé par réact noral et électron pour améliorer l'efficacité du développement.


Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

MantisBT
Mantis est un outil Web de suivi des défauts facile à déployer, conçu pour faciliter le suivi des défauts des produits. Cela nécessite PHP, MySQL et un serveur Web. Découvrez nos services de démonstration et d'hébergement.

Adaptateur de serveur SAP NetWeaver pour Eclipse
Intégrez Eclipse au serveur d'applications SAP NetWeaver.

VSCode Windows 64 bits Télécharger
Un éditeur IDE gratuit et puissant lancé par Microsoft

SublimeText3 version anglaise
Recommandé : version Win, prend en charge les invites de code !

ZendStudio 13.5.1 Mac
Puissant environnement de développement intégré PHP