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

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

从规范来看,Promise可以是:

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

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

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

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

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


当前回答

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

注意:只有在当前执行线程中出现某种中断,允许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承诺是否被履行/拒绝/解决?

其他回答

注意:此方法使用未文档化的Node.js内部构件,可以在没有警告的情况下进行更改。

在Node中,你可以使用process.binding('util')来同步确定promise的状态。getPromiseDetails(/* promise */);

这将返回:

[0,]表示未决,

[1, /* value */]表示已实现,或

[2, /* value */]表示拒绝。

const pending = new Promise(resolve => setTimeout(() => resolve('yakko')));;
const fulfilled = Promise.resolve('wakko');
const rejected = Promise.reject('dot');

[pending, fulfilled, rejected].forEach(promise => {
  console.log(process.binding('util').getPromiseDetails(promise));
});

// pending:   [0, ]
// fulfilled: [1, 'wakko']
// rejected:  [2, 'dot']

将其包装到一个helper函数中:

const getStatus = promise => ['pending', 'fulfilled', 'rejected'][
  process.binding('util').getPromiseDetails(promise)[0]
];

getStatus(pending); // pending
getStatus(fulfilled); // fulfilled
getStatus(rejected); // rejected

你可以在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

警告:process.binding(“跑龙套”)。节点16上的getPromiseDetails未定义!

基准:

候选人:

/**
 * https://stackoverflow.com/a/47009572/5318303
 */
const isPromisePending1 = (() => { // noinspection JSUnresolvedFunction
    const util = process.binding('util')  // noinspection JSUnresolvedFunction
    return promise => !util.getPromiseDetails(promise)[0]
})()

/**
 * https://stackoverflow.com/a/35852666/5318303
 */
const isPromisePending2 = (promise) => util.inspect(promise) === 'Promise { <pending> }'

/**
 * https://stackoverflow.com/a/35820220/5318303
 */
const isPromisePending3 = (promise) => {
    const t = {}
    return Promise.race([promise, t])
            .then(v => v === t, () => false)
}

测试的承诺:

const a = Promise.resolve()
const b = Promise.reject()
const c = new Promise(() => {})
const x = (async () => 1)()

运行基准:

const n = 1000000

console.time('isPromisePending1')
for (let i = 0; i < n; i++) {
    isPromisePending1(a)
    isPromisePending1(b)
    isPromisePending1(c)
    isPromisePending1(x)
}
console.timeEnd('isPromisePending1')

console.time('isPromisePending2')
for (let i = 0; i < n; i++) {
    isPromisePending2(a)
    isPromisePending2(b)
    isPromisePending2(c)
    isPromisePending2(x)
}
console.timeEnd('isPromisePending2')

console.time('isPromisePending3')
for (let i = 0; i < n; i++) {
    await isPromisePending3(a)
    await isPromisePending3(b)
    await isPromisePending3(c)
    await isPromisePending3(x)
}
console.timeEnd('isPromisePending3')

结果:

isPromisePending1: 440.694ms
isPromisePending2: 3.354s
isPromisePending3: 4.761s

显然isPromisePending1()太快了(8~10倍)!但它在节点16上不可用!(见上述警告)。

不,没有同步API,但这是我的async承诺(在@Matthijs的帮助下):

函数promiseState(p) { Const t = {}; 回报的承诺。种族([p t]) .then(v => (v == t)?"pending": " completed ", () => "rejected"); } var a = Promise.resolve(); var b = Promise.reject(); var c = new Promise(() => {}); promiseState (a)。Then (state => console.log(state));/ /实现 promiseState (b)。Then (state => console.log(state));/ /拒绝 promiseState (c)。Then (state => console.log(state));/ /等待

你可以在Node.js中使用一个(丑陋的)黑客,直到一个本地方法被提供:

util = require('util');

var promise1 = new Promise (function (resolve) {
}

var promise2 = new Promise (function (resolve) {

    resolve ('foo');
}

state1 = util.inspect (promise1);
state2 = util.inspect (promise2);

if (state1 === 'Promise { <pending> }') {

    console.log('pending'); // pending
}

if (state2 === "Promise { 'foo' }") {

    console.log ('foo') // foo
}