我一直在使用ES6 Promise。
通常,Promise是这样构造和使用的
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();
}
这很好,但是否有更简单的方法来做到这一点?如果不是,这是一个好的实践吗?
我们的解决方案是使用闭包来存储解析/拒绝函数,并附加一个函数来扩展承诺本身。
模式如下:
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');
不,没有其他方法可以做到这一点——我唯一能说的是这个用例不是很常见。就像Felix在评论中说的那样——你所做的将始终有效。
值得一提的是,promise构造函数以这种方式运行的原因是抛出安全——如果当你的代码在promise构造函数中运行时发生了你没有预料到的异常,它将变成拒绝,这种形式的抛出安全——将抛出的错误转换为拒绝是很重要的,有助于维护可预测的代码。
出于这个抛出安全的原因,承诺构造函数被选择而不是延迟(延迟是一种允许你正在做的事情的替代承诺构造方法)——至于最佳实践——我将传递元素并使用承诺构造函数:
var p = new Promise(function(resolve, reject){
this.onclick = resolve;
}.bind(this));
出于这个原因——只要可以使用promise构造函数而不是导出函数——我建议您使用它。无论何时你可以避免两者,避免两者和链。
注意,你永远不应该在if(condition)这样的情况下使用promise构造函数,第一个例子可以这样写:
var p = Promise[(someCondition)?"resolve":"reject"]();
有点晚了,但另一种方法是使用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
})
公认的答案是错误的。使用范围和引用非常简单,尽管这可能会让Promise纯粹主义者生气:
const createPromise = () => {
let resolver;
return [
new Promise((resolve, reject) => {
resolver = resolve;
}),
resolver,
];
};
const [ promise, resolver ] = createPromise();
promise.then(value => console.log(value));
setTimeout(() => resolver('foo'), 1000);
我们实际上是在创建promise时获取resolve函数的引用,并返回该引用,以便可以在外部设置它。
在一秒钟内控制台将输出:
> foo