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

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

从规范来看,Promise可以是:

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

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

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

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

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


当前回答

还有另一种优雅而俗气的方法来检查一个promise是否仍然挂起,只需将整个对象转换为字符串,并在inspect的帮助下检查它,就像这样:util.inspect(myPromise).includes("pending")。

在Node.js 8、9、10、11、12、13上测试

这里有一个完整的例子

const util = require("util")

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

(async ()=>{
  let letmesleep = sleep(3000)
  setInterval(()=>{
    console.log(util.inspect(letmesleep).includes("pending"))
  },1000)
})()

结果:

true
true
false
false
false

其他回答

你可以这样包装你的承诺

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

这里是一个更充实的QueryablePromise的es6版本,允许在第一次解析后进行链接和捕获,并立即解析或拒绝以保持api与本机Promise一致。

const PROMISE = Symbol('PROMISE') const tap = fn => x => (fn(x), x) const trace = label => tap(x => console.log(label, x)) class QueryablePromise { resolved = false rejected = false fulfilled = false catchFns = [] constructor(fn) { this[PROMISE] = new Promise(fn) .then(tap(() => { this.fulfilled = true this.resolved = true })) .catch(x => { this.fulfilled = true this.rejected = true return Promise.reject(x) }) } then(fn) { this[PROMISE].then(fn) return this } catch(fn) { this[PROMISE].catch(fn) return this } static resolve(x) { return new QueryablePromise((res) => res(x)) } static reject(x) { return new QueryablePromise((_, rej) => rej(x)) } } const resolvedPromise = new QueryablePromise((res) => { setTimeout(res, 200, 'resolvedPromise') }) const rejectedPromise = new QueryablePromise((_, rej) => { setTimeout(rej, 200, 'rejectedPromise') }) // ensure our promises have not been fulfilled console.log('test 1 before: is resolved', resolvedPromise.resolved) console.log('test 2 before: is rejected', rejectedPromise.rejected) setTimeout(() => { // check to see the resolved status of our promise console.log('test 1 after: is resolved', resolvedPromise.resolved) console.log('test 2 after: is rejected', rejectedPromise.rejected) }, 300) // make sure we can immediately resolve a QueryablePromise const immediatelyResolvedPromise = QueryablePromise.resolve('immediatelyResolvedPromise') // ensure we can chain then .then(trace('test 3 resolved')) .then(trace('test 3 resolved 2')) .catch(trace('test 3 rejected')) // make sure we can immediately reject a QueryablePromise const immediatelyRejectedPromise = QueryablePromise.reject('immediatelyRejectedPromise') .then(trace('test 4 resolved')) .catch(trace('test 4 rejected')) <script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>

使用惯用的原型,等待@jib的答案的使用。

Object.defineProperty(Promise.prototype, "state", {
    get: function(){
        const o = {};
        return Promise.race([this, o]).then(
            v => v === o ? "pending" : "resolved",
            () => "rejected");
    }
});

// usage: console.log(await <Your Promise>.state);
(async () => {
    console.log(await Promise.resolve(2).state);  // "resolved"
    console.log(await Promise.reject(0).state);   // "rejected"
    console.log(await new Promise(()=>{}).state); // "pending"
})();

注意,这个异步函数像同步函数一样“几乎”立即执行(或者实际上可能立即执行)。

我发现这个解决方案很简单,并且允许我继续使用本机承诺,但添加了有用的同步检查。我也不需要动用整个承诺库。

注意:只有在当前执行线程中出现某种中断,允许promise在检查同步结构之前执行时,这才有效。这使得它比我最初想象的用处更有限——尽管对我的用例仍然有用(感谢Benjamin Gruenbaum指出这一点)。

/**
 * This function allow you to modify a JS Promise by adding some status properties.
 * Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
 * But modified according to the specs of promises : https://promisesaplus.com/
 */
function MakeQuerablePromise(promise) {
    // Don't modify any promise that has been already modified.
    if (promise.isFulfilled) return promise;

    // Set initial state
    var isPending = true;
    var isRejected = false;
    var isFulfilled = false;

    // Observe the promise, saving the fulfillment in a closure scope.
    var result = promise.then(
        function(v) {
            isFulfilled = true;
            isPending = false;
            return v; 
        }, 
        function(e) {
            isRejected = true;
            isPending = false;
            throw e; 
        }
    );

    result.isFulfilled = function() { return isFulfilled; };
    result.isPending = function() { return isPending; };
    result.isRejected = function() { return isRejected; };
    return result;
}

wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); 
setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);

来自https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved,他们的答案是:是否有一种方法来判断一个ES6承诺是否被履行/拒绝/解决?

老问题有很多答案,但似乎没有一个建议我认为是最简单的解决方案:在承诺解决/拒绝上设置bool指示器。

类Promise2 { 构造函数(args) { let promise = new promise(…args); promise.then(() => promise。_resolved_ = true); promise.catch(() => promise。_rejected_ = true); 返回的诺言; } } let p = new promise (r => setTimeout(r, 3000)); setInterval(() => { Console.log('正在同步检查p是否已解析?”,p._resolved_); }, 1000);