paint-brush
Tout ce que vous devez savoir sur les promesses, les ficelles et l'évaluation paresseusepar@austingil
1,653 lectures
1,653 lectures

Tout ce que vous devez savoir sur les promesses, les ficelles et l'évaluation paresseuse

par Austin Gil5m2023/01/20
Read on Terminal Reader

Trop long; Pour lire

Au cours de la nouvelle année, je vais vous montrer comment faire des promesses d'être plus paresseux. Examinons un exemple de base de `Promise' . Ici, j'ai une fonction appelée sleep qui prend un temps en millisecondes et une valeur. Il renvoie une promesse qui exécutera un `setTimeout` pendant le nombre de millisecondes que nous devrions attendre.
featured image - Tout ce que vous devez savoir sur les promesses, les ficelles et l'évaluation paresseuse
Austin Gil HackerNoon profile picture

C'est le début d'une nouvelle année, et alors que beaucoup de gens promettent d'être plus actifs, je vais vous montrer comment faire des Promise d'être plus paresseux… Javascript Promise s, c'est.


Cela aura plus de sens dans un instant.

Tout d'abord, regardons un exemple de base de Promise . Ici, j'ai une fonction appelée sleep qui prend un temps en millisecondes et une valeur. Il renvoie une promesse qui exécutera un setTimeout pendant le nombre de millisecondes que nous devrions attendre ; puis la promesse se résout avec la valeur.


 /** * @template ValueType * @param {number} ms * @param {ValueType} value * @returns {Promise<ValueType>} */ function sleep(ms, value) { return new Promise((resolve) => { setTimeout(() => resolve(value), ms); }); }


Cela fonctionne comme ceci :


Console JavaScript avec le code "wait sleep(1000, 'Yawn & stretch')". Puis après une seconde, "'Bâillement et étirement'"


Nous pouvons attendre la fonction sleep avec les arguments 1000 et 'Yawn & stretch' , et après une seconde, la console enregistrera la chaîne, 'Yawn & stretch'.


Il n'y a rien de trop spécial à ce sujet. Il se comporte probablement comme vous vous en doutez, mais cela devient un peu bizarre si nous le stockons comme une variable à await plus tard, plutôt que d' await tout de suite la Promise renvoyée.


 const nap = sleep(1000, 'Yawn & stretch')


Maintenant, disons que nous faisons un autre travail qui prend du temps (comme taper l'exemple suivant), puis await la variable nap .


Taper dans la console JavaScript, "attendre la sieste" et voir immédiatement la réponse "'Bâillement et étirement'"

Vous pouvez vous attendre à un délai d'une seconde avant la résolution, mais en fait, il se résout immédiatement. Chaque fois que vous créez une Promise , vous instanciez la fonctionnalité asynchrone dont elle est responsable.


Dans notre exemple, au moment où nous définissons la variable nap , la Promise est créée qui exécute le setTimeout . Parce que je suis un type lent, la Promise sera résolue au moment où nous l' await .


En d'autres termes, les Promise sont impatientes. Ils n'attendent pas que vous les await .


Dans certains cas, c'est une bonne chose. Dans d'autres cas, cela pourrait entraîner une utilisation inutile des ressources. Pour ces scénarios, vous voudrez peut-être quelque chose qui ressemble à une Promise , mais qui utilise évaluation paresseuse pour instancier uniquement lorsque vous en avez besoin.


Avant de continuer, je veux vous montrer quelque chose d'intéressant.


Les Promise ne sont pas les seules choses qui peuvent être await en JavaScript. Si nous créons un Object simple avec une méthode .then() , nous pouvons en fait await cet objet comme n'importe quel Promise .


Console JavaScript avec le texte "wait { then: () => console.log('🙃') }" suivi de "🙃".

C'est un peu bizarre, mais cela nous permet également de créer différents objets qui ressemblent à Promise , mais qui n'en sont pas. Ces objets sont parfois appelés " Thénables “.


Dans cet esprit, créons un nouveau classer appelé LazyPromise qui étend le constructeur Promise intégré. L'extension de la promesse n'est pas strictement nécessaire, mais elle la fait ressembler davantage à une Promise en utilisant des choses comme instanceof .


 class LazyPromise extends Promise { /** @param {ConstructorParameters<PromiseConstructor>[0]} executor */ constructor(executor) { super(executor); if (typeof executor !== 'function') { throw new TypeError(`LazyPromise executor is not a function`); } this._executor = executor; } then() { this.promise = this.promise || new Promise(this._executor); return this.promise.then.apply(this.promise, arguments); } }


La partie sur laquelle se concentrer est la méthode then() . Il détourne le comportement par défaut d'une Promise standard d'attendre que la méthode .then() soit exécutée avant de créer une vraie Promise .


Cela évite d'instancier la fonctionnalité asynchrone jusqu'à ce que vous l'appeliez réellement. Et cela fonctionne si vous appelez explicitement .then() ou utilisez await .


Voyons maintenant ce qui se passe si nous remplaçons la Promise dans la fonction sleep d'origine par une LazyPromise . Encore une fois, nous assignerons le résultat à une variable nap .


 function sleep(ms, value) { return new LazyPromise((resolve) => { setTimeout(() => resolve(value), ms); }); } const nap = sleep(1000, 'Yawn & stretch')


Ensuite, nous prenons notre temps pour taper la ligne d' await nap et l'exécuter.


Taper dans la console JavaScript, "attendre la sieste" et après un délai d'une seconde, voir la réponse "'Bâillement et étirement'"


Cette fois, nous constatons un délai d'une seconde avant la résolution de la Promise , quel que soit le temps écoulé depuis la création de la variable.


(Notez que cette implémentation ne crée la nouvelle Promise qu'une seule fois et la référence dans les appels suivants. Donc, si nous devions l' await à nouveau, elle se résoudrait immédiatement comme n'importe quelle Promise normale)


Bien sûr, il s'agit d'un exemple trivial que vous ne trouverez probablement pas dans le code de production, mais de nombreux projets utilisent des objets de type Promise évalués paresseusement. L'exemple le plus courant est probablement celui des bases de données ORM et des constructeurs de requêtes tels que Knex.js ou alors prisme .


Considérez le pseudo-code ci-dessous. Il s'inspire de certains de ces générateurs de requête :


 const query = db('user') .select('name') .limit(10) const users = await query


Nous créons une requête de base de données qui va à la table "user" et sélectionne les dix premières entrées et renvoie leurs noms. En théorie, cela fonctionnerait bien avec une Promise régulière.


Mais que se passe-t-il si nous voulons modifier la requête en fonction de certaines conditions telles que les paramètres de chaîne de requête ? Ce serait bien de pouvoir continuer à modifier la requête avant d'attendre finalement la Promise .


 const query = db('user') .select('name') .limit(10) if (orderBy) { query.orderBy(orderBy) } if (limit) { query.limit(limit) } if (id) { query.where({ id: id }) } const users = await query


Si la requête de base de données d'origine était une Promise standard, elle instancierait la requête avec impatience dès que nous aurions attribué la variable, et nous ne serions pas en mesure de la modifier ultérieurement.


Avec l'évaluation paresseuse, nous pouvons écrire un code comme celui-ci qui est plus facile à suivre, améliore l'expérience du développeur et n'exécute la requête qu'une seule fois lorsque nous en avons besoin.


C'est un exemple où l'évaluation paresseuse est excellente. Cela peut également être utile pour des choses comme la création, la modification et l'orchestration des requêtes HTTP.


Les Promise paresseuses sont très cool pour les bons cas d'utilisation, mais cela ne veut pas dire qu'elles devraient remplacer toutes les Promise . Dans certains cas, il est avantageux d'instancier avec impatience et d'avoir la réponse prête dès que possible.


C'est un autre de ces scénarios "ça dépend". Mais la prochaine fois que quelqu'un vous demandera de faire une Promise , pensez à être paresseux ( ͡° ͜ʖ ͡°).


Merci beaucoup d'avoir lu. Si vous avez aimé cet article, n'hésitez pas Partagez-le . C'est l'un des meilleurs moyens de me soutenir. Vous pouvez également Inscrivez-vous à ma newsletter ou alors Suis moi sur Twitter si vous voulez savoir quand de nouveaux articles sont publiés.


Initialement publié le austingil.com .