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

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


当前回答

我为此写了一个小库。https://www.npmjs.com/package/@inf3rno/promise.exposed

我使用了别人写的工厂方法,但是我也重写了then, catch, finally方法,所以你也可以通过这些方法解决原来的承诺。

在没有外部执行人的情况下解决承诺:

const promise = Promise.exposed().then(console.log);
promise.resolve("This should show up in the console.");

从外部与执行器的setTimeout赛跑:

const promise = Promise.exposed(function (resolve, reject){
    setTimeout(function (){
        resolve("I almost fell asleep.")
    }, 100000);
}).then(console.log);

setTimeout(function (){
    promise.resolve("I don't want to wait that much.");
}, 100);

如果你不想污染全局命名空间,有一个无冲突模式:

const createExposedPromise = require("@inf3rno/promise.exposed/noConflict");
const promise = createExposedPromise().then(console.log);
promise.resolve("This should show up in the console.");

其他回答

我在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)

简单:

var promiseResolve, promiseReject;

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

promiseResolve();

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

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

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

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

我发现自己在某些情况下也忽略了Deferred模式。你总是可以在ES6的顶部创建一个:

export default class Deferred<T> {
    private _resolve: (value: T) => void = () => {};
    private _reject: (value: T) => void = () => {};

    private _promise: Promise<T> = new Promise<T>((resolve, reject) => {
        this._reject = reject;
        this._resolve = resolve;
    })

    public get promise(): Promise<T> {
        return this._promise;
    }

    public resolve(value: T) {
        this._resolve(value);
    }

    public reject(value: T) {
        this._reject(value);
    }
}

类版本,在Typescript中:

export class Deferred<T> {
    public readonly promise: Promise<T>
    private resolveFn!: (value: T | PromiseLike<T>) => void
    private rejectFn!: (reason?: any) => void

    public constructor() {
        this.promise = new Promise<T>((resolve, reject) => {
            this.resolveFn = resolve
            this.rejectFn = reject
        })
    }

    public reject(reason?: any): void {
        this.rejectFn(reason)
    }

    public resolve(param: T): void {
        this.resolveFn(param)
    }
}