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

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


当前回答

这里的许多答案与本文最后一个示例类似。 我正在缓存多个promise, resolve()和reject()函数可以分配给任何变量或属性。因此,我能够使这段代码更加紧凑:

function defer(obj) {
    obj.promise = new Promise((resolve, reject) => {
        obj.resolve = resolve;
        obj.reject  = reject;
    });
}

下面是一个使用这个版本的defer()将一个FontFace加载承诺与另一个异步进程结合的简化示例:

function onDOMContentLoaded(evt) {
    let all = []; // array of Promises
    glob = {};    // global object used elsewhere
    defer(glob);
    all.push(glob.promise);
    // launch async process with callback = resolveGlob()

    const myFont = new FontFace("myFont", "url(myFont.woff2)");
    document.fonts.add(myFont);
    myFont.load();
    all.push[myFont];
    Promise.all(all).then(() => { runIt(); }, (v) => { alert(v); });
}
//...
function resolveGlob() {
    glob.resolve();
}
function runIt() {} // runs after all promises resolved 

更新:如果你想封装对象,有2个选择:

function defer(obj = {}) {
    obj.promise = new Promise((resolve, reject) => {
        obj.resolve = resolve;
        obj.reject  = reject;
    });
    return obj;
}
let deferred = defer();

and

class Deferred {
    constructor() {
        this.promise = new Promise((resolve, reject) => {
            this.resolve = resolve;
            this.reject  = reject;
        });
    }
}
let deferred = new Deferred();

其他回答

是的,你可以。通过使用浏览器环境的CustomEvent API。以及在node.js环境中使用事件发射器项目。由于问题中的代码片段是针对浏览器环境的,因此这里有一个相同的工作示例。

函数myPromiseReturningFunction () { 返回新的承诺(resolve => { 窗口。addEventListener("myCustomEvent", (event) => { 解决(event.detail); }) }) } myPromiseReturningFunction()。然后(result => { alert(结果) }) . getelementbyid (p)。addEventListener("click", () => { 窗口。dispatchEvent(new CustomEvent("myCustomEvent", {detail: "它起作用了!"})) }) <p id="p">点击我</p>

我希望这个答案对你有用!

简单:

var promiseResolve, promiseReject;

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

promiseResolve();

我发现自己在某些情况下也忽略了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);
    }
}

有点晚了,但另一种方法是使用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
})

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

如果你绑定并捕获Deferred对象,那么它完全实现了Promise API,你可以将它视为Promise并等待它等等。

⚠️ Editor's Note: I don't recommend this kind of pattern anymore since at the time of writing, Promise.prototype.finally was not a thing yet, then it became a thing… This could happen to other methods so I recommend you augment the promise instance with resolve and reject functions instead: function createDeferredPromise() { let resolve let reject const promise = new Promise((thisResolve, thisReject) => { resolve = thisResolve reject = thisReject }) return Object.assign(promise, {resolve, reject}) } Go upvote someone else's answer.

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.finally = this._promise.finally.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();