Résoudre Javascript Promesse en dehors de la portée de la fonction

J'ai utilisé ES6 Promise.

Habituellement, une promesse est construite et utilisée comme ça

new Promise(function(resolve, reject){ if (someCondition){ resolve(); } else { reject(); } }); 

Mais j'ai fait quelque chose comme ci-dessous pour résoudre le problème à l'extérieur par souci de flexibilité.

 var outsideResolve; var outsideReject; new Promise(function(resolve, reject) { outsideResolve = resolve; outsideReject = reject; }); 

Et ensuite

 onClick = function(){ outsideResolve(); } 

Cela fonctionne bien, mais y a-t-il un moyen plus facile de le faire? Sinon, est-ce une bonne pratique?

Non, il n'y a pas d'autre moyen de le faire – la seule chose que je peux dire, c'est que ce cas d'utilisation n'est pas très commun. Comme l'a dit Felix dans le commentaire, ce que vous faites fonctionneront constamment.

Il vaut la peine de mentionner que la raison pour laquelle le constructeur prometteur se comporte de cette façon est de jeter la sécurité – si une exception que vous ne prévoyez pas se produit alors que votre code fonctionne dans le constructeur prometteur, il se transformera en un rejet, cette forme de sécurité jetée – la conversion des erreurs jetées Les rejets sont importants et contribuent à maintenir un code prévisible.

Pour ce motif de sécurité, le constructeur promesse a été choisi au cours des différends (ce qui constitue une méthode de construction de promesses alternatives qui permettent ce que vous faites) – en ce qui a trait aux meilleures pratiques – je passerais l'élément et utiliser le constructeur prometteur à la place:

 var p = new Promise(function(resolve, reject){ this.onclick = resolve; }.bind(this)); 

Pour cette raison – chaque fois que vous pouvez utiliser le constructeur promesse sur l'exportation des fonctions – je vous recommande de l'utiliser. Chaque fois que vous pouvez éviter les deux – éviter les deux et la chaîne.

Notez que vous ne devriez jamais utiliser le constructeur prometteur pour des choses comme if(condition) , le premier exemple pourrait être écrit comme suit:

 var p = Promise[(someCondition)?"resolve":"reject"](); 

simple:

 var promiseResolve, promiseReject; var promise = new Promise(function(resolve, reject){ promiseResolve = resolve; promiseReject = reject; }); promiseResolve(); 

Un peu tard pour le parti ici, mais une autre façon de le faire serait d'utiliser un objet différé . Vous avez essentiellement la même quantité de boilerplate, mais il est pratique si vous voulez les transmettre et éventuellement résoudre en dehors de leur définition.

Mise en œuvre naïve:

 class Deferred { constructor() { this.promise = new Promise((resolve, reject)=> { this.reject = reject this.resolve = resolve }) } } function asyncAction() { var dfd = new Deferred() setTimeout(()=> { dfd.resolve(42) }, 500) return dfd.promise } asyncAction().then(result => { console.log(result) // 42 }) 

Version ES5:

 function Deferred() { var self = this; this.promise = new Promise(function(resolve, reject) { self.reject = reject self.resolve = resolve }) } function asyncAction() { var dfd = new Deferred() setTimeout(function() { dfd.resolve(42) }, 500) return dfd.promise } asyncAction().then(function(result) { console.log(result) // 42 }) 

Notre solution était d'utiliser des fermetures pour stocker les fonctions de résolution / rejet et, en plus, associer une fonction pour étendre la promesse elle-même.

Voici le modèle:

 function getPromise() { var _resolve, _reject; var promise = new Promise((resolve, reject) => { _reject = reject; _resolve = resolve; }); promise.resolve_ex = (value) => { _resolve(value); }; promise.reject_ex = (value) => { _reject(value); }; return promise; } 

Et l'utiliser:

 var promise = getPromise(); promise.then(value => { console.info('The promise has been fulfilled: ' + value); }); promise.resolve_ex('hello'); // or the reject version //promise.reject_ex('goodbye'); 

Profitez-en et aimez-vous!

 function createPromise(handler){ var _resolve, _reject; var promise = new Promise(function(resolve, reject){ _resolve = resolve; _reject = reject; handler(resolve, reject); }) promise.resolve = _resolve; promise.reject = _reject; return promise; } var promise = createPromise() promise.then(function(data){ alert(data) }) promise.resolve(200) // resolve from outside 

Je suis venu avec quelque chose qui est fondamentalement une variante Javascript minimale du modèle wait / notify (sans protection de la section critique, car Javascript n'a pas ce problème).

Fiddle ici .

Code:

 // create some monitors var monitors = [ new Monitor(1), // rough deadline new Monitor(), new Monitor(), new Monitor() ]; // register event handlers (on "notify event") for (var i = 0; i < monitors.length; ++i) { var monitor = monitors[i]; monitor.i = i; monitor.wait .bind(monitor) .then(function(result) { console.log('Success ' + this.i + ': ' + result); }) .catch(function(err) { console.error('Failure ' + this.i + ': ' + err); }); } // notify like a bawss Promise .delay(100) .then(function() { monitors[0].notifyResolve('hi! :)'); monitors[1].notifyReject('hi! :('); monitors[2].notifyResolve('hi! :)'); // forgot about the fourth monitor: it'll timeout }); // Monitor class function Monitor(timeoutMillis) { timeoutMillis = timeoutMillis || 1000; var resolve, reject; var isResolved = false, err, result; var promise = new Promise(function(_resolve, _reject) { if (isResolved) { if (err) { _reject(err) } else { _resolve(result); } } else { resolve = _resolve; reject = _reject; } }); // make sure, promise will be fulfilled if (timeoutMillis >= 0) { // negative value means: no timeout setTimeout(function() { if (!isResolved) { this.notifyReject('timeout'); } }.bind(this), timeoutMillis); } this.wait = promise; this.notifyResolve = function(_result) { if (isResolved) return; isResolved = true; if (resolve) { resolve(_result); } else { // remember result until Promise ctor callback is called result = _result; } }; this.notifyReject = function(_err) { if (isResolved) return; isResolved = true; if (reject) { reject(_err); } else { // remember result until Promise ctor callback is called err = _err; } }; }; 

Résultat:

Échec 0: timeout

Succès 2: salut! 🙂

Échec 1: salut! 🙁

Échec 3: timeout

Pour votre cas d'utilisation, il existe certainement une meilleure façon.

 const promise = new Promise(function(resolve, reject){ if (someCondition){ resolve() } else { reject() } }) 

est équivalent à:

 const promise = Promise[someCondition ? 'resolve' : 'reject']() 

Et plus tard:

 onClick = function(){ promise .then(() => /** handle resolve */) .catch(err => /** handle reject */) } 

Les promesses sont utiles pour le travail asynchrone et cet exemple n'a pas de travail asynchrone, ce qui en fait un anti-modèle. Vous êtes préférable d'utiliser des promesses avec des implémentations telles que récupérer des promesses de retour natives et utiliser le style de constructeur uniquement lorsque vous travaillez avec une interface asynchrone incompatible (rappels de nœud).

Le code le plus propre n'est aucun code.