解决function范围外的Javascript Promise

我一直在使用ES6 Promise。

通常,承诺是这样构build和使用的

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

但为了灵活性,我一直在做下面这样的事情。

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

然后

 onClick = function(){ outsideResolve(); } 

这工作正常,但有一个更简单的方法来做到这一点? 如果不是,这是一个很好的做法?

不,没有其他办法可以做到这一点 – 我唯一能说的就是这个用例不是很常见。 就像费利克斯在评论中所说 – 你所做的一切都会一直工作。

值得一提的是,承诺构造函数以这种方式行为的原因是抛出安全性 – 如果你没有预料到的exception发生,而你的代码在承诺构造函数内运行,它将变成拒绝,这种抛出安全的forms – 将抛出的错误转换为拒绝是重要的,有助于维护可预测的代码。

对于这个抛出安全的原因,承诺构造函数被select了延期(这是一个替代承诺的build设方式,让你在做什么) – 至于最佳实践 – 我会传递元素和使用承诺的构造函数,而不是:

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

出于这个原因 – 每当你可以使用承诺构造函数来导出函数 – 我build议你使用它。 每当你可以避免两个 – 避免两个和连锁。

请注意,你不应该使用承诺构造函数的东西,如if(condition) ,第一个例子可以写成:

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

简单:

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

这里晚了点,但另一种方法是使用Deferred对象。 你基本上有相同数量的样板文件,但是如果你想传递它们并且可能在他们的定义之外解决,那么它是方便的。

天真实施:

 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 }) 

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 }) 

享受MYYYYYYYYY个人解决scheme! 我在2015年提出了我的框架。 我打电话给这种types的承诺任务

 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 

我想出了一些基本上是等待/通知模式的简单Javascript变体(sans critical section protection,因为Javascript没有这个问题)。

在这里拨弄 。

码:

 // 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; } }; }; 

结果:

失败0:超时

成功2:嗨! 🙂

失败1:嗨! 🙁

失败3:超时

我们的解决scheme是使用闭包来存储parsing/拒绝函数,并附加一个函数来扩展承诺本身。

这是模式:

 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; } 

并使用它:

 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'); 

对于你的用例来说,肯定有更好的办法。

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

相当于:

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

然后:

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

Promise对于asynchronous工作很有用,而且这个例子没有asynchronous工作,使它成为一个反模式。 您最好使用承诺实现,例如本地返回promise的实现,并且仅在使用不兼容的asynchronous接口(节点callback)时使用构造函数样式。

最干净的代码根本就没有代码。

我喜欢@JonJaques的回答,但我想更进一步。

如果你绑定then catch Deferred对象,那么它完全实现了Promise API,你可以把它当作promise并await它。

 class DeferredPromise { constructor() { this._promise = new Promise((resolve, reject) => { // assign the resolve and reject functions to `this` // making them usable on the class instance this.resolve = resolve; this.reject = reject; }); // bind `then` and `catch` to implement the same interface as Promise this.then = this._promise.then.bind(this._promise); this.catch = this._promise.catch.bind(this._promise); this[Symbol.toStringTag] = 'Promise'; } } const deferred = new DeferredPromise(); console.log('waiting 2 seconds...'); setTimeout(() => { deferred.resolve('whoa!'); }, 2000); async function someAsyncFunction() { const value = await deferred; console.log(value); } someAsyncFunction();