Il est temps de s'enfermer
Les fonctions asynchrones en Javascript ne sont pas vraiment parallèles. À partir de ES2017, Javascript prend en charge les appels de fonction simultanés. La différence est très bien résumée par Madhavan Nagarajan dans la déclaration suivante (le lien peut être trouvé dans l'addendum).
La simultanéité consiste à traiter beaucoup de choses à la fois. Le parallélisme consiste à faire beaucoup de choses à la fois.
L'implémentation de la simultanéité de Javascript est réduite dans ses fonctionnalités pour permettre une API simple et très robuste à utiliser. Les fonctions asynchrones ne peuvent pas être interrompues et n'ont aucun concept de propriétés volatiles lorsqu'elles traitent l'accès à la même variable par différents appels asynchrones. L'implémentation détaillée des fonctions asynchrones d'ES2017 est hors de portée de cet article, mais le point principal que je veux faire passer est que jusqu'à présent, le parallélisme n'était pas intégré à Javascript et au Web et, par conséquent, aucune gestion particulière des mutations parallèles du même entité. Mais cela change maintenant avec l'introduction de la « Web Locks API ».
Un pour tous et tous pour un
Maintenant que les applications Web progressives vous offrent de véritables architectures multithread avec l'introduction de WebWorkers et de ServiceWorker, les choses ont changé. Le vrai parallélisme est possible dans les applications Web, et donc le désir d'outils plus sophistiqués pour traiter le code parallèle se fait sentir.
Un verrou est un mécanisme permettant de demander l'accès aux ressources et d'avoir la garantie qu'un seul processus à un moment donné a réellement accès. Verrouiller les ressources de cette manière évite un grand nombre de zones de conflit qui pourraient autrement survenir.
Une ressource n'est qu'un espace de noms, identifié par une chaîne. Et votre demande d'accès à la ressource est tout aussi simple, car vous n'avez besoin que de l'ID et d'un rappel de fonction, probablement asynchrone, pour implémenter la « Web Lock API ». Lorsqu'une fonction asynchrone est terminée, le verrou est libéré et les autres requêtes peuvent à nouveau y accéder.
/*
* A simple demonstration of the Web Lock API.
* Note that this example has been taken from
* MDN's awesome documentation, linked in the
* addendum.
*/
async function foo(){
// A common async function that you already know.
const data = await getData();
// Request the lock.
// Note that we can simply await the locked call!
await navigator.locks.request('lock_resource_id', async lock => {
// The lock has been acquired.
// At this point, this call has exlusive access
// to the resource 'lock_resource_id'.
await updateDb(data);
// Now the lock will be released.
});
// The lock has been released.
// Continuse with plain async calls.
await updateUi();
}
En raison de l'état expérimental de cette nouvelle API, vous devez la traiter comme une fonctionnalité facultative dans votre code avec une solution de secours valide disponible.
/**
* Due to the usage of web locks in core parts
* of your app, actually using the API this way
* might introduce more problems then it could solve.
*
* Therefore a thorough specification in your app
* has to be implementation before using this feature.
*/
async function update(){
if(navigator?.locks){
// Run logic with lock.
} else {
// Use fallback.
}
}
Pour mieux illustrer cette nouvelle API, regardons un exemple simple. Supposons que vous ayez une PWA multithread avec votre processus principal et deux WebWorkers. Votre application utilise également un IndexDB, avec un code personnalisé qui synchronise les modifications vers et depuis la base de données avec le cloud. À l'aide de « Web Lock API » dans ce scénario, chaque processus peut demander l'accès au verrou défini pour synchroniser les modifications apportées à la base de données, en veillant à ce qu'aucune autre mutation ne soit exécutée pendant cet appel.
Notez que « Web Lock API » ne concerne pas tant la mutation d'une seule variable sans effets secondaires dans votre application Web (bien que cela puisse clairement être un cas d'utilisation), mais plutôt la gestion des appels de fonction dans une architecture parallèle qui conduirait autrement à effets secondaires négatifs.
Beaucoup plus à apprendre
Cet article n'a donné qu'une introduction à la nouvelle "API Web Locks", qui est actuellement à l'état expérimental et principalement prise en charge par les navigateurs basés sur Chromium. L'API offre plus d'options décrites ici et vaut la peine d'y jeter un coup d'œil.