507 votes

Aren ' t promet quelques rappels ?

J'ai été en développement JavaScript pour quelques années et je ne comprends pas ces histoires au sujet de promesses.

Il semble que tout ce que je faire est de changer:

api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

Qui je pourrais utiliser une bibliothèque comme async de toute façon, avec quelque chose comme:

api().then(function(result){
     api2().then(function(result2){
          api3().then(function(result3){
               // do work
          });
     });
});

Ce qui est plus de code et moins lisible. Je n'ai pas gagner quoi que ce soit ici, c'est pas tout d'un coup comme par magie "à plat". Pour ne pas mentionner avoir à convertir des choses de promesses.

Donc, quel est le grand tapage à propos de promesses ici?

709voto

Oscar Paz Points 3644

Les promesses ne sont pas des rappels. Une promesse qui représente l' avenir de la suite d'une opération asynchrone. Bien sûr, l'écriture de la façon dont vous le faites, vous avez peu de profit. Mais si vous écrivez de la façon dont il doit être fait, vous pouvez écrire du code asynchrone dans une façon qui ressemble à du code synchrone et est beaucoup plus facile à suivre:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
});

Certes, pas beaucoup moins de code, mais beaucoup plus lisible.

Mais ce n'est pas la fin. Venez découvrir les véritables avantages: Que faire si vous voulez vérifier pour toute erreur dans l'une de ces étapes? Il serait l'enfer pour le faire avec des rappels, mais avec la promesse, est un morceau de gâteau:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
});

À peu près la même chose qu'un try { ... } catch bloc.

Encore mieux:

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
}).then(function() {
     //do something whether there was an error or not
     //like hiding an spinner if you were performing an AJAX request.
});

Et même mieux. Si ces 3 appels à l' api, api2, api3 peuvent s'exécuter simultanément (ce qu'ils ont été les appels AJAX), mais vous avez besoin d'attendre pour les trois? Sans promesses, vous devez avoir à créer une sorte de contre. Avec des promesses, à l'aide de l'ES6 notation, est un autre morceau de gâteau et très soigné:

Promise.all([api(), api2(), api3()]).then(function(result) {
    //do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
    //handle the error. At least one of the promises rejected.
});

Espérons vous voir Promesses dans une nouvelle lumière.

197voto

Bergi Points 104242

Oui, les Promesses sont des rappels asynchrones. Ils ne peuvent rien faire que les rappels ne peut pas le faire, et vous rencontrent les mêmes problèmes avec l'asynchronie comme de simples rappels.

Cependant, les Promesses sont plus que juste des rappels. Ils sont d'une très puissant de l'abstraction, de permettre à plus propre et mieux, code fonctionnel avec moins de risques d'erreurs standard.

Alors, quelle est l'idée principale?

Les promesses sont des objets représentant le résultat d'une seule personne (asynchrone) le calcul. Ils résoudre à ce résultat qu'une seule fois. Il y a quelques choses ce que cela signifie:

Promet de mettre en œuvre un modèle observateur:

  • Vous n'avez pas besoin de connaître les rappels qui va utiliser la valeur avant la fin de la tâche.
  • Au lieu d'attendre les rappels comme les arguments de vos fonctions, vous pouvez facilement return une Promesse objet
  • La promesse de stocker la valeur, et vous pouvez de manière transparente ajouter un rappel à chaque fois que vous le souhaitez. Il sera appelée lorsque le résultat est disponible. "La transparence" signifie que lorsque vous avez une promesse et d'ajouter un rappel, il n'est pas de faire une différence dans votre code si le résultat a encore arrivé - l'API et les contrats sont les mêmes, la simplification de la mise en cache/memoisation beaucoup.
  • Vous pouvez ajouter plusieurs rappels facilement

Les promesses sont chainable (monadique, si vous voulez):

  • Si vous avez besoin pour transformer la valeur d'une promesse représente, vous carte une fonction de transformation sur la promesse et de revenir une nouvelle promesse que représente la transformée de résultat. Vous ne pouvez pas synchrone obtenir la valeur de l'utiliser d'une certaine façon, mais vous pouvez facilement soulever la transformation dans la promesse contexte. Pas de passe-partout pour les rappels.
  • Si vous voulez à la chaîne de deux tâches asynchrones, vous pouvez utiliser l' .then() méthode. Il faudra un callback appelée avec le premier résultat, et retourne une promesse pour la suite de la promesse que le callback retourne.

Cela vous semble compliqué? Temps pour un exemple de code.

var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
    var p2 = api2(); // returning a promise
    return p2; // The result of p2 …
}); // … becomes the result of p3

// So it does not make a difference whether you write
api1().then(function(api1Result) {
    return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
    return api2();
}).then(console.log)

L'aplatissement ne vient pas par magie, mais vous pouvez le faire facilement. Pour votre fortement imbriqués exemple, la quasi-équivalente

api1().then(api2).then(api3).then(/* do-work-callback */);

Si le fait de voir le code de ces méthodes permet de comprendre, d' ici la une promesse lib en quelques lignes.

Quel est le grand tapage au sujet des promesses?

La Promesse d'abstraction permet de beaucoup mieux la composabilité des fonctions. Par exemple, à côté d' then de l'enchaînement, l' all fonction crée une promesse pour le résultat combiné de plusieurs parallèle d'attente de promesses.

Dernière mais pas moins Promet viennent avec système intégré de gestion des erreurs. Le résultat du calcul peut être que la promesse est rempli avec une valeur, ou s'il est rejeté avec raison. Toutes la composition des fonctions de gérer cela automatiquement et propager les erreurs dans la promesse de chaînes, de sorte que vous n'avez pas besoin de s'en soucier explicitement partout - contrairement à la plaine-rappel de la mise en œuvre. En fin de compte, vous pouvez ajouter un dédié erreur de rappel pour tous produits d'exceptions.

Pour ne pas mentionner avoir à convertir des choses de promesses.

C'est assez banal en fait avec une bonne promesse de bibliothèques, de voir Comment puis-je convertir un rappel de l'API de promesses?

5voto

Kjell Schubert Points 1

Les promesses ne sont pas des rappels, programmez les deux idiomes qui facilitent la programmation asynchrone. En utilisant un async/attendent-du style de programmation à l’aide de générateurs qui retournent des promesses ou des coroutines pourrait considérer une 3e tel idiome. Une comparaison de ces idiomes dans différents langages de programmation (y compris le Javascript) est ici : https://github.com/KjellSchubert/promise-future-task

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X