我一直在使用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();
}

这很好,但是否有更简单的方法来做到这一点?如果不是,这是一个好的实践吗?


当前回答

简单:

var promiseResolve, promiseReject;

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

promiseResolve();

其他回答

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

模式如下:

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"]();

我想分享一些不同的东西,这是这个话题的延伸。

有时,您希望“任务承诺”在解析时自动在相同的地址(属性或变量)重新创建。可以创建一个外部解析器来完成这个任务。

一个带有外部解析器的重复承诺的例子。无论何时调用解析器,都会在相同的地址/变量/属性处创建一个新的承诺。

let resolvePromise;
let thePromise;

const setPromise = (resolve) => {
  resolvePromise = () => {
    resolve();
    thePromise = new Promise(setPromise);   
  }
}
thePromise = new Promise(setPromise);

(async () => {
  let i = 0;
  while (true) {
    let msg = (i % 2 === 0) ? 'Tick' : 'Tock';
    document.body.innerHTML = msg;
    setTimeout(resolvePromise, 1000);
    await thePromise;
    i++;
  }
})();

https://jsfiddle.net/h3zvw5xr

helper方法可以减轻这种额外的开销,并给您同样的jQuery感觉。

function Deferred() {
    let resolve;
    let reject;
    const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
    });
    return { promise, resolve, reject };
}

用法是

const { promise, resolve, reject } = Deferred();
displayConfirmationDialog({
    confirm: resolve,
    cancel: reject
});
return promise;

它类似于jQuery

const dfd = $.Deferred();
displayConfirmationDialog({
    confirm: dfd.resolve,
    cancel: dfd.reject
});
return dfd.promise();

不过,在用例中,这种简单的本机语法就可以了

return new Promise((resolve, reject) => {
    displayConfirmationDialog({
        confirm: resolve,
        cancel: reject
    });
});

我在2015年为我的框架提出了一个解决方案。我把这种类型的承诺称为任务

function createPromise(handler){
  var resolve, reject;

  var promise = new Promise(function(_resolve, _reject){
    resolve = _resolve; 
    reject = _reject;
    if(handler) handler(resolve, reject);
  })
  
  promise.resolve = resolve;
  promise.reject = reject;
  return promise;
}


// create
var promise = createPromise()
promise.then(function(data){ alert(data) })

// resolve from outside
promise.resolve(200)