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

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


当前回答

首先在浏览器或节点上启用——allow-native -syntax

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

onClick = function () {
    %ResolvePromise(p, value)
}

其他回答

不,没有其他方法可以做到这一点——我唯一能说的是这个用例不是很常见。就像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"]();

感谢每个在这篇文章中发帖的人。我创建了一个模块,其中包括前面描述的Defer()对象以及在其上构建的其他一些对象。它们都利用Promise和简洁的Promise回调语法在程序中实现通信/事件处理。

延迟:可以远程解决失败的承诺(在承诺体之外) 延迟:在给定时间后自动解决的承诺 TimeOut:承诺在给定时间后自动失败。 循环:使用promise语法管理事件的可重新触发承诺 队列:基于承诺链的执行队列。

Rp = require("openpromise")

https://github.com/CABrouwers/openpromise https://www.npmjs.com/package/openpromise

只是另一种从外部解决承诺的方法

 class Lock {
        #lock;  // Promise to be resolved (on  release)
        release;  // Release lock
        id;  // Id of lock
        constructor(id) {
            this.id = id
            this.#lock = new Promise((resolve) => {
                this.release = () => {
                    if (resolve) {
                        resolve()
                    } else {
                        Promise.resolve()
                    }
                }
            })
        }
        get() { return this.#lock }
    }

使用

let lock = new Lock(... some id ...);
...
lock.get().then(()=>{console.log('resolved/released')})
lock.release()  // Excpected 'resolved/released'

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

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

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

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对象。你基本上有相同数量的样板文件,但是如果你想要传递它们并且可能在它们的定义之外解析,这很方便。

天真的实现:

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