Est-ce une promesse héréditaire?

Juste pour le plaisir / l'apprentissage, je voulais prolonger Promise et trouver, via des gens incroyablement compétents sur stackoverflow, qu'il ne peut pas être fait avec l'ancienne syntaxe standard. Mais je voulais de toute façon, alors j'ai pensé à créer ma propre classe IPromise qui compose un objet Promise et permet à d'autres d'en hériter en utilisant l'ancienne syntaxe non ES6.

Je veux savoir comment cette implémentation diffère d'un univers où la promesse intégrale est directement héréditaire, et si quelqu'un a une idée, pourquoi les implémenteurs de Promise ne sont pas autorisés à l'héritage avec l'ancienne syntaxe.

Voici ma classe IPromise extensible / héritable:

// Inheritable Promise IPromise = function(executor) { this.promise = new Promise(executor); }; IPromise.prototype = Object.create(Promise.prototype); IPromise.prototype.constructor = IPromise; IPromise.prototype.catch = function(fail) { return this.promise.catch(fail); } IPromise.prototype.then = function(success, fail) { return this.promise.then(success, fail); }; // Usage // No different to builtin Promsise (new IPromise(function(resolve, reject) { return resolve(true); })) .then(function(response) { console.log('IPromise then is like Promise then', response); }) .catch(function(error) { console.log('IPromise catch is like Promise catch', error); }); 

Voici un exemple de l'extension pour un lot ajax qui attend toutes les requêtes à compléter indépendamment du fait qu'elles échouent. Un peu différent de la fonctionnalité intégrée.

 // Inheriting // You can inherit from IPromise like you would any normal class. BatchAjax = function(queries) { var batchAjax = this; this.queries = queries; this.responses = []; this.errorCount = 0; IPromise.call(this, function(resolve, reject) { batchAjax.executor(resolve, reject); }); }; BatchAjax.prototype = Object.create(IPromise.prototype); BatchAjax.prototype.constructor = BatchAjax; BatchAjax.prototype.executor = function(resolve, reject) { var batchAjax = this; $.each(this.queries, function(index) { var query = this; query.success = function (result) { batchAjax.processResult(result, index, resolve, reject); }; query.error = function (jqXhr, textStatus, errorThrown) { batchAjax.errorCount++; var result = { jqXhr: jqXhr, textStatus: textStatus, errorThrown: errorThrown }; batchAjax.processResult(result, index, resolve, reject); }; $.ajax(query); }); }; BatchAjax.prototype.processResult = function(result, index, resolve, reject) { this.responses[index] = result; if (this.responses.length === this.queries.length) { if (this.errorCount === 0) { resolve(this.responses); } else { reject(this.responses); } } }; // Usage // Inheriting from IPromise is boring, which is good. var baseUrl = 'https://jsonplaceholder.typicode.com'; (new BatchAjax([{url: baseUrl + '/todos/4'}, {url: baseUrl + '/todos/5'}])) .then(function(response) {console.log('Yay! ', response);}) .catch(function(error) {console.log('Aww! ', error);}); 

Gardez à l'esprit que j'apprends juste et que cela ne doit pas être utile, c'est juste intéressant. Mais n'hésitez pas à donner des critiques brutales, je suis ouvert à l'idée que c'est une chose stupide à faire:)

Merci de regarder et désolé pour tout le code!

Edit: Voici la question à laquelle j'étais à l'origine tenter d'étendre la promesse: Extension d'une promesse en javascript . Il ne semble pas fonctionner avec l'ancienne syntaxe, car le constructeur Promise lance une erreur Type s'il remarque qu'il initialise quelque chose qui n'est pas une promesse (je pense).

Edit2: le commentaire de jfriend00 a souligné quelque chose d'intéressant. Qu'est-ce que l'IPromise devrait revenir? En ce moment, c'est juste une promesse, mais devrait-il être un IPromise?

 IPromise.prototype.then = function(success, fail) { this.promise.then(success, fail); return new IPromise(whatGoesHere?); }; 

Ou une instance de n'importe quelle classe l'a hérité.

 IPromise.prototype.then = function(success, fail) { this.promise.then(success, fail); return new this.constructor(whatGoesHere?); }; 

Ou pourrait-il simplement le renvoyer?

 IPromise.prototype.then = function(success, fail) { this.promise.then(success, fail); return this; }; 

Je connais Promise.then renvoie une promesse, mais je ne sais pas comment cette promesse est configurée ou devrait se comporter. C'est pourquoi j'ai évité le problème et je viens de retourner la Promesse à partir de ce.promise.then. Y a-t-il d'autres solutions sensibles?

Oui, votre IPromise se comporte surtout comme une vraie Promise . Mais par exemple, vous ne pouvez pas appeler des méthodes prometteuses natives:

 var p = new Promise(function(resolve) { return resolve(true); }); var ip = new IPromise(function(resolve) { return resolve(true); }); Promise.prototype.then.call(p, v => console.log(v)); Promise.prototype.then.call(ip, v => console.log(v)); // TypeError 

Si vous souhaitez que vos instances IPromise soient des promesses réelles, elles doivent être initialisées par Promise . Ce constructeur ajoute quelques slots internes comme [[PromiseState]] que vous ne pouvez pas imiter. Mais les promesses créées par Promise héritent de Promise.prototype et, avant ES6, il n'existe aucun moyen standard de modifier [[Prototype]] avec IPromise.prototype après que l'objet a été créé.

En utilisant les classes ES6,

 class IPromise extends Promise { // You can add your own methods here } 

Ce qui suit a été suggéré par les commentaires de jfriend00.

Lorsque vous chaîne IPromises, vous n'obtiendrez pas un objet IPromise après le chaînage parce que votre IPromise.prototype.then() renvoie simplement une promesse normale avec return this.promise.then(success, fail);

Moi: devrait IPromise.then juste faire:

 this.promise.then(success, fail); 

Et puis un de ces?

 return new IPromise(whatGoesHere?); return new this.constructor(whatGoesHere?); return this; 

C'est l'une des raisons pour lesquelles il est vraiment désordonné d'étendre les promesses. L'infrastructure elle-même crée de nouvelles promesses avec chaque appel .then () et ne fournit pas un moyen simple de vous connecter à cela sans l'infrastructure sous-jacente qui supporte la sous-classement. Si vous regardez ici, ce support existe dans certains environnements. Mais, j'ai toujours trouvé que je pouvais résoudre mes problèmes d'une autre manière. Donc, je n'essaierai pas de pirater ma propre sous-classement car il semble probable qu'elle ait des trous.

Retournez-moi (tobuslieven) en train de parler à nouveau maintenant. Je suis d'accord avec cela, mais je vais toujours garder cette classe à l'esprit et l'utiliser si je vois une opportunité. Je pense que le retour de Promise au lieu d'IPromise est réalisable et c'est vraiment amusant d'être capable d'étendre ses Promesses comme ça.

Donc, ma réponse est oui, peut-être assez bonne et vaut la peine d'avoir recours à l'utilisation réelle quelque part.