Maison >interface Web >js tutoriel >Une introduction aux objets différés de jQuery
Les développeurs JavaScript ont longtemps utilisé des fonctions de rappel pour effectuer plusieurs tâches. Un exemple très courant consiste à ajouter un rappel via la fonction addEventListener()
pour effectuer diverses actions lorsque des événements tels que des clics ou des touches sont déclenchés. La fonction de rappel est simple et facile à utiliser et convient aux scénarios simples. Cependant, lorsque la complexité des pages Web augmente et que de nombreuses opérations asynchrones doivent être effectuées en parallèle ou séquentiellement, la fonction de rappel devient difficile à gérer.
ECMAScript 2015 (également connu sous le nom d'ECMAScript 6) introduit une méthode native pour gérer ces situations: Promise. Si vous ne connaissez pas la promesse, vous pouvez lire l'article "Aperçu de JavaScript Promise". JQuery fournit et fournit toujours sa propre version de Promise, appelé l'objet différé. Quelques années avant que la promesse ne soit introduite dans Ecmascript, l'objet différé a déjà été introduit dans jQuery. Cet article discutera des objets différés et des problèmes qu'ils essaient de résoudre.
Points clés
resolve()
, reject()
, done()
, fail()
, then()
, catch()
Gestion des erreurs améliorées: Brief History
L'objet différé a été introduit dans JQuery 1.5, qui est un utilitaire calculable en chaîne pour enregistrer plusieurs rappels dans une file d'attente de rappel, appeler la file d'attente de rappel et passer le succès ou le statut de défaillance de toute fonction synchrone ou asynchrone. Depuis lors, c'est un sujet de discussion, certaines critiques et de nombreux changements. Certains exemples de critiques incluent "vous avez manqué le point de la promesse" et "JavaScript Promise et pourquoi jQuery est la mise en œuvre du mal".
Avec l'objet Promise, différé représente la mise en œuvre de la promesse par JQuery. Dans les versions jQuery 1.x et 2.x, l'objet différé suit les promesses CommonJS / une proposition. Cette proposition est utilisée comme base de la proposition de promesses / A, et la promesse native a été construite sur cette proposition. Comme indiqué dans l'introduction, la raison pour laquelle JQuery ne suit pas les promesses / une proposition est qu'elle a mis en œuvre une promesse bien avant la proposition de la proposition.Parce que jQuery est un pionnier, et il y a une différence dans la façon d'utiliser la promesse dans Pure Javascript et JQuery 1.x et 2.x en raison de problèmes de compatibilité en arrière. En outre, puisque JQuery suit différentes propositions, la bibliothèque est incompatible avec d'autres bibliothèques qui implémentent la promesse, comme la bibliothèque Q.
L'interopérabilité avec la promesse native, telle que mise en œuvre dans ECMAScript 2015, a été améliorée dans le prochain JQuery 3. Les signatures de la méthode principale (then()
) sont encore légèrement différentes pour des raisons de compatibilité vers l'arrière, mais le comportement est plus conforme à la norme.
Fonction de rappel dans jQuery
Pour comprendre pourquoi vous devrez peut-être utiliser un objet différé, discutons d'un exemple. Lors de l'utilisation de jQuery, il utilise souvent sa méthode Ajax pour effectuer des demandes asynchrones. Par exemple, supposons que vous développez une page Web qui envoie des demandes AJAX à l'API GitHub. Votre objectif est de récupérer la liste du référentiel de l'utilisateur, de trouver le référentiel récemment mis à jour, de trouver le premier fichier avec le nom "readme.md" et enfin de récupérer le contenu du fichier. Selon cette description, chaque demande Ajax ne peut démarrer qu'après la fin de l'étape précédente. En d'autres termes, les demandes doivent être exécutées dans l'ordre .
Convertir cette description en pseudo-code (notez que je n'utilise pas la vraie API GitHub), nous obtenons:
<code class="language-javascript">var username = 'testuser'; var fileToSearch = 'README.md'; $.getJSON('https://api.github.com/user/' + username + '/repositories', function(repositories) { var lastUpdatedRepository = repositories[0].name; $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/files', function(files) { var README = null; for (var i = 0; i < files.length; i++) { if (files[i].name.indexOf(fileToSearch) >= 0) { README = files[i].path; break; } } $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/file/' + README + '/content', function(content) { console.log('The content of the file is: ' + content); }); }); });</code>Comme vous pouvez le voir dans cet exemple, en utilisant la fonction de rappel, nous devons nicher les appels pour exécuter les demandes AJAX dans l'ordre que nous voulons. Cela rend le code moins lisible. Il existe de nombreux rappels imbriqués ou des rappels indépendants qui doivent être synchronisés, souvent appelés "Hellback Hell".
Pour une petite amélioration, vous pouvez extraire la fonction nommée de la fonction en ligne anonyme que j'ai créée. Cependant, ce changement n'a pas beaucoup aidé et nous nous retrouvons toujours dans l'enfer de rappel. Des objets différés et prometteurs sont nécessaires pour le moment.
Objets différés et prometteurs
Les objets différés peuvent être utilisés lors de l'exécution d'opérations asynchrones telles que les demandes et les animations AJAX. Dans jQuery, l'objet Promise est créé à partir d'un objet différé ou d'un objet jQuery. Il a un sous-ensemble des méthodes d'objets différées:, always()
, done()
, fail()
, state()
, et then()
. Je couvrirai ces méthodes et d'autres dans la section suivante.
Si vous venez du monde natif JavaScript, vous pouvez être confus par l'existence de ces deux objets. Pourquoi y a-t-il deux objets (différés et promesses) alors que JavaScript n'en a qu'un (promesse)? Pour expliquer les différences et leurs cas d'utilisation, je vais prendre la même métaphore que j'ai utilisée dans mon livre jQuery in Action, Third Edition.
Si vous écrivez une fonction qui gère les opérations asynchrones et doit renvoyer les valeurs (peut également être une erreur ou aucune valeur), vous utilisez généralement un objet différé. Dans ce cas, votre fonction est le producteur de la valeur et vous souhaitez empêcher l'utilisateur de modifier l'état de différé. Utilisez l'objet Promise lorsque vous êtes un consommateur d'une fonction.
Pour clarifier ce concept, supposons que vous souhaitiez implémenter une fonction timeout()
basée sur des promesses (je vais vous montrer le code de cet exemple dans une section ultérieure de cet article). Vous êtes responsable de la rédaction d'une fonction qui doit attendre un temps donné (auquel cas la valeur n'est pas retournée). Cela fait de vous un producteur. Le consommateur de votre fonction ne se soucie pas de l'analyse ou du rejet. L'utilisateur doit seulement être en mesure d'ajouter des fonctions à exécuter lorsque le différé est terminé, échoué ou progressé. De plus, vous souhaitez vous assurer que l'utilisateur ne peut pas analyser ou rejeter tout seul. Pour y parvenir, vous devez retourner l'objet Promise différé créé dans la fonction timeout()
, au lieu des reportages lui-même. Ce faisant, vous pouvez vous assurer que personne ne peut appeler les méthodes timeout()
ou resolve()
sauf la fonction reject()
.
Vous pouvez en savoir plus sur la différence entre les objets différés et prometteurs de jQuery dans cette question StackOverflow.
Maintenant que vous savez quels sont ces objets, jetons un coup d'œil aux méthodes disponibles.
Méthode différée
Les objets différés sont très flexibles et fournissent un moyen de répondre à tous vos besoins. Il peut être créé en appelant la méthode jQuery.Deferred()
comme suit:
<code class="language-javascript">var username = 'testuser'; var fileToSearch = 'README.md'; $.getJSON('https://api.github.com/user/' + username + '/repositories', function(repositories) { var lastUpdatedRepository = repositories[0].name; $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/files', function(files) { var README = null; for (var i = 0; i < files.length; i++) { if (files[i].name.indexOf(fileToSearch) >= 0) { README = files[i].path; break; } } $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/file/' + README + '/content', function(content) { console.log('The content of the file is: ' + content); }); }); });</code>
ou, utilisez $ raccourci:
<code class="language-javascript">var deferred = jQuery.Deferred();</code>
Après la création, l'objet différé expose plusieurs méthodes. Ignorez ces méthodes obsolètes ou supprimées, ce sont:
always(callbacks[, callbacks, ..., callbacks])
: Ajoutez le gestionnaire à appeler lorsque l'objet différé est analysé ou rejeté. done(callbacks[, callbacks, ..., callbacks])
: Ajoutez le gestionnaire à appeler lorsque l'objet différé est analysé. fail(callbacks[, callbacks, ..., callbacks])
: Ajoutez le gestionnaire à appeler lorsque l'objet différé est rejeté. notify([argument, ..., argument])
: Appelez le progressCallbacks
de l'objet différé avec le paramètre donné. notifyWith(context[, argument, ..., argument])
: Appelez le progressCallbacks
de l'objet différé avec le contexte et les paramètres donnés. progress(callbacks[, callbacks, ..., callbacks])
: Ajoutez le gestionnaire à appeler lorsque l'objet différé génère une notification de progression. promise([target])
: Renvoie l'objet Promise différé. reject([argument, ..., argument])
: défend l'objet différé et appelle tout failCallbacks
avec le paramètre donné. rejectWith(context[, argument, ..., argument])
: défend l'objet différé et appelle tout failCallbacks
avec le contexte et les paramètres donnés. resolve([argument, ..., argument])
: analyser l'objet différé et appeler tout doneCallbacks
avec le paramètre donné. resolveWith(context[, argument, ..., argument])
: analyse l'objet différé et appelle tout doneCallbacks
avec le contexte et les paramètres donnés. state()
: Déterminez l'état actuel de l'objet différé. then(resolvedCallback[, rejectedCallback[, progressCallback]])
: Ajoutez le gestionnaire à appeler lorsque l'objet différé est analysé, rejeté ou est toujours en cours. Les descriptions de ces méthodes me donnent la possibilité de souligner la différence entre la documentation JQuery et les termes utilisés par la spécification ECMAScript. Dans la spécification ECMAScript, lorsque la promesse a été terminée ou rejetée, il est dit que la promesse a été résolue. Cependant, dans la documentation de JQuery, le mot "résolu" est utilisé pour faire référence à un état appelé "accompli" dans la spécification ECMAScript.
En raison des nombreuses méthodes fournies, toutes les méthodes ne peuvent pas être couvertes dans cet article. Cependant, dans la section suivante, je vous montrerai quelques exemples de différé et de promesse d'utilisation. Dans le premier exemple, nous remplacerons les extraits de code vérifiés dans la section "Fonctions de rappel dans jQuery", mais nous utiliserons ces objets au lieu des fonctions de rappel. Dans le deuxième exemple, je clarifierai l'analogie du producteur-consommateur discutée.
Exécuter les demandes AJAX en utilisant l'ordre différé
Dans cette section, je vais montrer comment utiliser l'objet différé et certaines de ses méthodes pour améliorer la lisibilité du code développé dans la section "Fonctions de rappel dans jQuery". Avant de creuser plus profondément, nous devons comprendre les méthodes dont nous avons besoin.
En fonction de nos besoins et de la liste des méthodes fournies, il est évident que nous pouvons utiliser les méthodes done()
ou then()
pour gérer des situations réussies. Étant donné que beaucoup d'entre vous s'étaient habitués à l'objet Promise de JavaScript, dans cet exemple, j'utiliserai la méthode then()
. Une différence importante entre ces deux méthodes est que then()
est capable de transférer la valeur du paramètre reçu à d'autres appels then()
, done()
, fail()
ou progress()
définis après.
Le résultat final est le suivant:
<code class="language-javascript">var username = 'testuser'; var fileToSearch = 'README.md'; $.getJSON('https://api.github.com/user/' + username + '/repositories', function(repositories) { var lastUpdatedRepository = repositories[0].name; $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/files', function(files) { var README = null; for (var i = 0; i < files.length; i++) { if (files[i].name.indexOf(fileToSearch) >= 0) { README = files[i].path; break; } } $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/file/' + README + '/content', function(content) { console.log('The content of the file is: ' + content); }); }); });</code>
Comme vous pouvez le voir, le code est plus facile à lire, car nous pouvons diviser l'ensemble du processus en plusieurs petites étapes au même niveau (à propos de l'indentation).
Créer une fonction SetTimeout Settimeout basée sur des promesses
Comme vous le savez, setTimeout()
est une fonction qui exécute une fonction de rappel après une durée donnée. Les deux éléments (fonction de rappel et temps) doivent être fournis comme paramètres. Supposons que vous souhaitiez enregistrer le message à la console en une seconde. En utilisant la fonction setTimeout()
, vous pouvez y parvenir avec le code ci-dessous:
<code class="language-javascript">var deferred = jQuery.Deferred();</code>
Comme vous pouvez le voir, le premier paramètre est la fonction à exécuter, et le deuxième paramètre est le nombre de millisecondes à attendre. Cette fonction fonctionne bien depuis des années, mais que se passe-t-elle si vous devez introduire la latence dans la chaîne différée?
Dans le code suivant, je vais vous montrer comment utiliser l'objet Promise fourni par jQuery pour développer une fonction setTimeout()
prometteur. Pour ce faire, j'utiliserai la méthode promise()
de l'objet différé.
Le résultat final est le suivant:
<code class="language-javascript">var deferred = $.Deferred();</code>
Dans cette liste, je définis une fonction appelée timeout()
qui enveloppe la fonction native setTimeout()
de JavaScript. À l'intérieur timeout()
, je crée un nouvel objet différé pour gérer une tâche asynchrone qui implique l'analyse de l'objet différé après le nombre spécifié de millisecondes. Dans ce cas, la fonction timeout()
est le producteur de la valeur, il crée donc l'objet différé et renvoie l'objet Promise. Ce faisant, je m'assure que l'appelant (consommateur) de la fonction ne peut pas analyser ou rejeter l'objet différé à volonté. En fait, l'appelant ne peut utiliser que des méthodes telles que done()
et fail()
pour ajouter les fonctions à exécuter.
Différence entre jQuery 1.x / 2.x et jQuery 3
Dans le premier exemple en utilisant différé, nous avons développé un extrait de code qui recherche un fichier avec le nom "Readme.md", mais nous n'avons pas pris en compte le cas où un tel fichier n'a pas pu être trouvé. Cette situation peut être considérée comme un échec. Lorsque cela se produit, nous voulons peut-être briser la chaîne d'appels et sauter directement à la fin. Pour ce faire, une exception est naturellement lancée et l'attraper en utilisant la méthode fail()
, tout comme la méthode catch()
de JavaScript.
Dans les bibliothèques conformes aux promesses / a et promesses / a (par exemple, jQuery 3.x), les exceptions lancées sont converties en rejets et les rappels échoués sont appelés (par exemple, ajoutés avec fail()
). Cela reçoit l'exception en tant que paramètre.
Dans jQuery 1.x et 2.x, les exceptions non apprises arrêteront l'exécution du programme. Ces versions permettent des exceptions lancées à la bouillonnement, atteignant généralement window.onerror
. Si aucune fonction n'est définie pour gérer cette exception, un message d'exception s'affiche et l'exécution du programme est interrompue.
Pour mieux comprendre les différents comportements, consultez cet exemple:
<code class="language-javascript">var username = 'testuser'; var fileToSearch = 'README.md'; $.getJSON('https://api.github.com/user/' + username + '/repositories', function(repositories) { var lastUpdatedRepository = repositories[0].name; $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/files', function(files) { var README = null; for (var i = 0; i < files.length; i++) { if (files[i].name.indexOf(fileToSearch) >= 0) { README = files[i].path; break; } } $.getJSON('https://api.github.com/user/' + username + '/repository/' + lastUpdatedRepository + '/file/' + README + '/content', function(content) { console.log('The content of the file is: ' + content); }); }); });</code>
Dans jQuery 3.x, ce code écrit les messages "première fonction de défaillance" et "deuxième fonction de réussite" sur la console. La raison en est que, comme je l'ai mentionné précédemment, la spécification indique que l'exception lancée doit être convertie en rejet et que le rappel raté doit être appelé en utilisant l'exception. De plus, une fois l'exception traitée (gérée par un rappel raté transmis au second then()
dans notre exemple), la fonction réussie suivante doit être exécutée (dans ce cas, le rappel réussi est passé au troisième then()
dans ce cas) ).
Dans jQuery 1.x et 2.x, aucune autre fonction n'est exécutée, sauf la première fonction (la fonction qui lance l'erreur), vous ne verrez que le message "Erreur non apprise: un message d'erreur".
Pour améliorer encore sa compatibilité avec ECMAScript 2015, JQuery 3 a également ajouté une nouvelle méthode dans les objets différés et prometteurs catch()
. C'est une façon d'exécuter un gestionnaire lorsqu'un objet différé est rejeté ou que son objet Promise est dans un état rejeté. Sa signature est la suivante:
<code class="language-javascript">var deferred = jQuery.Deferred();</code>
Cette méthode n'est qu'un raccourci vers then(null, rejectedCallback)
.
Conclusion
Dans cet article, je vous ai présenté la mise en œuvre de la promesse de JQuery. La promesse vous permet d'éviter la nécessité d'utiliser des astuces désagréables pour synchroniser les fonctions asynchrones parallèles et les rappels imbriqués ...
En plus de montrer quelques exemples, j'ai également couvert comment JQuery 3 améliore l'interopérabilité avec la promesse native. Malgré la mise en évidence des différences entre JQuery plus âgée et ECMAScript 2015, Reforred est toujours un outil très puissant dans votre boîte à outils. En tant que développeur professionnel, vous vous retrouverez à l'utiliser fréquemment à mesure que le projet devient plus difficile.
FAQ pour les objets différés jQuery (FAQ)
(La partie FAQ est omise ici parce que l'article est trop long et n'a pas grand-chose à voir avec le thème principal de l'article. Si nécessaire, vous pouvez poser la question de la FAQ séparément.)
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!