我有一个纯JavaScript承诺(内置实现或poly-fill):

var promise = new promise(函数(解析,拒绝){/*…* /});

从规范来看,Promise可以是:

" settle "和" resolved " “解决”和“拒绝” “等待”

我有一个用例,我希望同步审问承诺并确定:

承诺达成了吗? 如果是,承诺解决了吗?

我知道我可以使用#then()来安排在Promise改变状态后异步执行的工作。我不是在问你该怎么做。

这个问题是关于Promise状态的同步询问。我怎样才能做到这一点呢?


当前回答

在节点中,写入未记录的内部进程。

> process.binding('util').getPromiseDetails(Promise.resolve({data: [1,2,3]}));
[ 1, { data: [ 1, 2, 3 ] } ]

> process.binding('util').getPromiseDetails(Promise.reject(new Error('no')));
[ 2, Error: no ]

> process.binding('util').getPromiseDetails(new Promise((resolve) => {}));
[ 0, <1 empty item> ]

其他回答

对于原生JavaScript承诺,不存在这样的同步检查API。用本土的承诺是不可能做到的。规范没有指定这样的方法。

用户域库可以做到这一点,如果你的目标是一个特定的引擎(比如v8),并且可以访问平台代码(也就是说,你可以在核心中编写代码),那么你可以使用特定的工具(比如私有符号)来实现这一点。这是非常具体的,但不是在用户领域。

你可以这样包装你的承诺

function wrapPromise(promise) {
  var value, error,
      settled = false,
      resolved = false,
      rejected = false,
      p = promise.then(function(v) {
        value = v;
        settled = true;
        resolved = true;
        return v;
      }, function(err) {
        error = err;
        settled = true;
        rejected = true;
        throw err;
      });
      p.isSettled = function() {
        return settled;
      };
      p.isResolved = function() {
        return resolved;
      };
      p.isRejected = function() {
        return rejected;
      };
      p.value = function() {
        return value;
      };
      p.error = function() {
        return error;
      };
      var pThen = p.then, pCatch = p.catch;
      p.then = function(res, rej) {
        return wrapPromise(pThen(res, rej));
      };
      p.catch = function(rej) {
        return wrapPromise(pCatch(rej));
      };
      return p;
}

你可以在Promise.prototype中添加一个方法。它是这样的:

编辑:第一个解决方案不能正常工作,就像这里的大多数答案一样。它返回“pending”直到异步函数“。然后”被调用,这不是立即发生的。(使用Promise.race的解决方案也是如此)。我的第二个解决方案解决了这个问题。

if (window.Promise) {
    Promise.prototype.getState = function () {
        if (!this.state) {
            this.state = "pending";
            var that = this;
            this.then(
                function (v) {
                    that.state = "resolved";
                    return v;
                },
                function (e) {
                    that.state = "rejected";
                    return e;
                });
        }
        return this.state;
    };
}

你可以在任何承诺上使用它。为例:

myPromise = new Promise(myFunction);
console.log(myPromise.getState()); // pending|resolved|rejected

第二个(也是正确的)解决方案:

if (window.Promise) {
    Promise.stateable = function (func) {
        var state = "pending";
        var pending = true;
        var newPromise = new Promise(wrapper);
        newPromise.state = state;
        return newPromise;
        function wrapper(resolve, reject) {
            func(res, rej);
            function res(e) {
                resolve(e);
                if (pending) {
                    if (newPromise)
                        newPromise.state = "resolved";
                    else
                        state = "resolved";
                    pending = false;
                }
            }
            function rej(e) {
                reject(e);
                if (pending) {
                    if (newPromise)
                        newPromise.state = "rejected";
                    else
                        state = "rejected";
                    pending = false;
                }
            }
        }
    };
}

并使用它:

注意:在这个解决方案中,您不必使用“new”操作符。

myPromise = Promise.stateable(myFunction);
console.log(myPromise.state); // pending|resolved|rejected

从Node.js版本8开始,您现在可以使用智能检查包来同步检查本机承诺(没有任何危险的黑客)。

这是我使用的将来模式:(https://github.com/Smallscript-Corp)

启用同步和异步fn使用 使事件模式与异步行为统一

class XPromise extends Promise {
  state = 'pending'
  get settled() {return(this.state !== 'pending')}
  resolve(v,...a) {
    this.state = 'resolved'
    return(this.resolve_(this.value = v,...a))
  }
  reject(e,...a) {
    this.state = 'rejected'
    return(this.reject_(this.value = (e instanceof Error) ? e : XPromise.Error(e),...a))
  }
  static Error(e) {const v = Error('value-rejected'); v.value = e; return(v)}
  static Future(fn,...args) { // FactoryFn
    let r,t,fv = new XPromise((r_,t_) => {r=r_;t=t_})
    fv.resolve_ = r; fv.reject_  = t;
    switch(typeof fn) {
      case 'undefined': break; case 'function': fn(fv,...args); break;
      default: fv.resolve(fn)
    }
    return(fv)
  }
}
global.Future = XPromise.Future

然后你可以创建可以使用同步和异步函数来解决的未来价值实例;支持统一处理事件。

你可以用它来写一个像这样的模式:

async doSomething() {
  // Start both - logically async-parallel
  const fvIsNetworkOnLine = this.fvIsNetworkOnline
  const fvAuthToken = this.fvAuthToken
  // await both (order not critical since both started/queued above)
  await fvAuthToken
  await fvIsNetworkOnLine
  // ... we can check the future values here if needed `fv.resolved`, `fv.state` etc
  // ... do dependent workflow here ...
}
onNetworkOnLine(fIsOnline) {
  // We utilize the `fv.settled` below, and use the event to `settle` it etc
  if(fIsOnline) {
    if(this.fvNetworkAvailable_)
      this.fvNetworkAvailable_.resolve(true)
    this.fvNetworkAvailable_ = undefined
  }
  else if(this.fvNetworkAvailable_.settled) {
    this.fvNetworkAvailable_ = undefined
  }
}
get fvNetworkAvailable() {
  if(navigator.onLine)
    return true
  else if(this.fvNetworkAvailable_)
    return this.fvNetworkAvailable_
  return (this.fvNetworkAvailable_ = Future())
}
get fvAuthToken() {
  if(this.fvAuthToken_)
    return this.fvAuthToken_
  const authTokenFv = async fv => {
    // ... handle retry logic etc here ...
  }
  return(this.fvAuthToken_ = Future(authTokenFv))
}