Article original : Limiting concurrent operations in JavaScript
Par Maciej Cieślar
Généralement, la machine qui exécute notre code dispose de ressources limitées. Tout faire en même temps peut non seulement nuire, mais aussi bloquer notre processus et le faire cesser de répondre complètement.
Lorsque nous voulons explorer 100 sites web, nous devrions en explorer, par exemple, 5 à la fois, afin de ne pas utiliser toute la bande passante disponible. Dès qu'un site web est exploré, le suivant est prêt à être traité.
En général, toutes les opérations "lourdes" doivent être réparties dans le temps. Elles ne doivent pas être exécutées toutes en même temps, pour de meilleures performances et pour économiser des ressources.
Installation
Si vous êtes familier avec mon précédent article sur l'implémentation des promesses, vous allez remarquer de nombreuses similitudes.
class Concurrently<T = any> {
private tasksQueue: (() => Promise<T>)[] = [];
private tasksActiveCount: number = 0;
private tasksLimit: number;
public constructor(tasksLimit: number) {
if (tasksLimit < 0) {
throw new Error('La limite ne peut pas être inférieure à 0.');
}
this.tasksLimit = tasksLimit;
}
private registerTask(handler) {
this.tasksQueue = [...this.tasksQueue, handler];
this.executeTasks();
}
private executeTasks() {
while (this.tasksQueue.length && this.tasksActiveCount < this.tasksLimit) {
const task = this.tasksQueue[0];
this.tasksQueue = this.tasksQueue.slice(1);
this.tasksActiveCount += 1;
task()
.then((result) => {
this.tasksActiveCount -= 1;
this.executeTasks();
return result;
})
.catch((err) => {
this.tasksActiveCount -= 1;
this.executeTasks();
throw err;
});
}
}
public task(handler: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) =>
this.registerTask(() =>
handler()
.then(resolve)
.catch(reject),
),
);
}
}
export default Concurrently;
Nous enregistrons une tâche donnée en l'ajoutant à notre tasksQueue puis nous appelons executeTasks.
Maintenant, nous exécutons autant de tâches que notre limite nous le permet — une par une. Chaque fois en ajoutant 1 à notre compteur appelé tasksActiveCount.
Lorsque la tâche exécutée se termine, nous retirons 1 de tasksActiveCount et appelons à nouveau executeTasks.
Ci-dessous, nous pouvons voir un exemple de son fonctionnement.
La limite est fixée à 3. Les deux premières tâches prennent très longtemps à être traitées. Nous pouvons voir le troisième "slot" s'ouvrir de temps en temps, permettant à la tâche suivante dans la file d'attente d'être exécutée.
Il y a toujours trois tâches, ni plus, ni moins.
Exécution de tâches lourdes et légères avec une limite de 3.
Vous pouvez voir le code dans le dépôt.
Merci beaucoup d'avoir lu ! Pouvez-vous penser à une autre façon d'atteindre le même effet ? Partagez-les ci-dessous.
Si vous avez des questions ou des commentaires, n'hésitez pas à les mettre dans la section des commentaires ci-dessous ou envoyez-moi un message.
Consultez mes réseaux sociaux !
Publié à l'origine sur www.mcieslar.com le 28 août 2018.