Lorsque je fais de la programmation asynchrone à un seul thread, je connais bien deux techniques principales. La plus courante consiste à utiliser des rappels. Cela signifie qu'il faut transmettre à la fonction qui agit de manière asynchrone une fonction de rappel en tant que paramètre. Lorsque l'opération asynchrone se termine, le rappel est appelé.
Certains jQuery
codes typiques conçus de cette façon:
$.get('userDetails', {'name': 'joe'}, function(data) {
$('#userAge').text(data.age);
});
Cependant, ce type de code peut devenir très confus et hautement imbriqué lorsque nous souhaitons effectuer des appels asynchrones supplémentaires les uns après les autres, une fois l’opération terminée.
Une deuxième approche consiste donc à utiliser les promesses. Une promesse est un objet qui représente une valeur qui pourrait ne pas encore exister. Vous pouvez y définir des rappels, qui seront appelés lorsque la valeur sera prête à être lue.
La différence entre Promises et l'approche traditionnelle des rappels réside dans le fait que les méthodes asynchrones renvoient désormais de manière synchrone les objets Promise, pour lesquels le client définit un rappel. Par exemple, un code similaire utilisant Promises dans AngularJS:
$http.get('userDetails', {'name': 'joe'})
.then(function(response) {
$('#userAge').text(response.age);
});
Ma question est donc la suivante: existe-t-il réellement une différence? La différence semble être purement syntaxique.
Existe-t-il une raison plus profonde d’utiliser une technique plutôt que l’autre?
Réponses:
Il est juste de dire que les promesses ne sont que du sucre syntaxique. Tout ce que vous pouvez faire avec des promesses, vous pouvez le faire avec des rappels. En fait, les implémentations les plus prometteuses vous permettent de convertir les deux à tout moment.
La principale raison pour laquelle les promesses sont souvent meilleures est qu'elles sont plus composables , ce qui signifie approximativement que combiner plusieurs promesses "ne fonctionne pas", alors que combiner plusieurs rappels ne le fait souvent pas. Par exemple, il est simple d'affecter une promesse à une variable et d'y attacher des gestionnaires supplémentaires ultérieurement, ou même d'attacher un gestionnaire à un grand groupe de promesses qui ne sera exécutée qu'une fois toutes les promesses résolues. Bien que vous puissiez en quelque sorte émuler ces rappels, il faut beaucoup plus de code, il est très difficile de le faire correctement et le résultat final est généralement beaucoup moins gérable.
L'un des moyens les plus importants (et les plus subtils) d'obtenir une composition est la gestion uniforme des valeurs de retour et les exceptions non détectées. Avec les rappels, la manière dont une exception est gérée peut dépendre entièrement du choix de nombreux rappels imbriqués, et de la fonction qui prend des rappels dans sa mise en œuvre. Avec des promesses, vous savez qu’une exception qui échappe à une fonction de rappel sera interceptée et transmise au gestionnaire d’erreur que vous avez fourni avec
.error()
ou.catch()
.Pour l'exemple que vous avez donné d'un simple rappel par rapport à une seule promesse, il est vrai qu'il n'y a pas de différence significative. C'est quand vous avez un million de rappels contre un million de promesses que le code basé sur les promesses a tendance à être beaucoup plus agréable.
Voici une tentative de code hypothétique écrit avec des promesses, suivi de rappels qui devraient être suffisamment complexes pour vous donner une idée de ce dont je parle.
Avec des promesses:
Avec rappels:
Même sans promesse, il existe peut-être des solutions astucieuses pour réduire la duplication de code dans la version des callbacks, mais toutes celles auxquelles je peux penser se résument à mettre en œuvre quelque chose de très prometteur.
la source
yield
promesses éd. L’avantage ici est que vous avez la possibilité de mélanger des structures de flux de contrôles natifs, dont le nombre d’opérations asynchrones peut varier. Je vais ajouter une version qui montre cela.then(callback)
méthode sur Promise qui accepte un rappel (au lieu d'une méthode sur l'API acceptant ce rappel) n'a rien à faire avec IoC. Promise introduit un niveau d'indirection utile pour la composition, le chaînage et la gestion des erreurs (en fait, la programmation orientée ferroviaire), mais le rappel n'est toujours pas exécuté par le client, il n'y a donc pas vraiment absence d'IoC.