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

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

从规范来看,Promise可以是:

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

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

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

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

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


当前回答

更新:2019

Bluebird.js提供了这个:http://bluebirdjs.com/docs/api/isfulfilled.html

var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());

如果您更喜欢创建自己的包装器,这里有一个关于它的不错的博客。

因为JavaScript是单线程的,所以很难找到一个足够常见的用例来证明将其放在规范中是正确的。知道承诺是否被解决的最佳位置是在.then()中。测试Promise是否被履行将创建一个轮询循环,这很可能是错误的方向。

如果你想同步推理异步代码,Async /await是一个很好的结构。

await this();
await that();
return 'success!';

另一个有用的调用是Promise.all()

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

当我第一次得到这个答案时,这就是我正在寻找的用例。

其他回答

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

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

警告: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上不可用!(见上述警告)。

还有另一种优雅而俗气的方法来检查一个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

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

> 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> ]

我为此做了一个包裹。与这里的大多数其他答案不同,它不会接受未经处理的拒绝。

npm install p-state
import timers from 'timers/promises';
import {promiseStateSync} from 'p-state';

const timeoutPromise = timers.setTimeout(100);

console.log(promiseStateSync(timeoutPromise));
//=> 'pending'

await timeoutPromise;

console.log(promiseStateSync(timeoutPromise));
//=> 'fulfilled'