我有一个纯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

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

你可以和Promise.resolve赛跑 它不是同步的,但现在就发生了

function promiseState(p, isPending, isResolved, isRejected) {
  Promise.race([p, Promise.resolve('a value that p should not return')]).then(function(value) {
    if (value == 'a value that p should not return') {
      (typeof(isPending) === 'function') && isPending();
    }else {
      (typeof(isResolved) === 'function') && isResolved(value);
    }
  }, function(reason) {
    (typeof(isRejected) === 'function') && isRejected(reason);
  });
}

一个用于测试的小脚本,并理解异步的含义

var startTime = Date.now() - 100000;//padding trick "100001".slice(1) => 00001
function log(msg) {
  console.log((""+(Date.now() - startTime)).slice(1) + ' ' + msg);
  return msg;//for chaining promises
};

function prefix(pref) { return function (value) { log(pref + value); return value; };}

function delay(ms) {
  return function (value) {
    var startTime = Date.now();
    while(Date.now() - startTime < ms) {}
    return value;//for chaining promises
  };
}
setTimeout(log, 0,'timeOut 0 ms');
setTimeout(log, 100,'timeOut 100 ms');
setTimeout(log, 200,'timeOut 200 ms');

var p1 = Promise.resolve('One');
var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "Two"); });
var p3 = Promise.reject("Three");

p3.catch(delay(200)).then(delay(100)).then(prefix('delayed L3 : '));

promiseState(p1, prefix('p1 Is Pending '), prefix('p1 Is Resolved '), prefix('p1 Is Rejected '));
promiseState(p2, prefix('p2 Is Pending '), prefix('p2 Is Resolved '), prefix('p2 Is Rejected '));
promiseState(p3, prefix('p3 Is Pending '), prefix('p3 Is Resolved '), prefix('p3 Is Rejected '));

p1.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p2.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p3.catch(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
log('end of promises');
delay(100)();
log('end of script');

延迟(0)的结果(注释在延迟中的while)

00001 end of promises
00001 end of script
00001 Level 1 : One
00001 Level 1 : Three
00001 p1 Is Resolved One
00001 p2 Is Pending undefined
00001 p3 Is Rejected Three
00001 Level 2 : One
00001 Level 2 : Three
00001 delayed L3 : Three
00002 Level 3 : One
00002 Level 3 : Three
00006 timeOut 0 ms
00100 timeOut 100 ms
00100 Level 1 : Two
00100 Level 2 : Two
00101 Level 3 : Two
00189 timeOut 200 ms

与firefox(chrome保持顺序)测试的结果

00000 end of promises
00100 end of script
00300 Level 1 : One
00300 Level 1 : Three
00400 p1 Is Resolved One
00400 p2 Is Pending undefined
00400 p3 Is Rejected Three
00400 Level 2 : One
00400 Level 2 : Three
00400 delayed L3 : Three
00400 Level 3 : One
00400 Level 3 : Three
00406 timeOut 0 ms
00406 timeOut 100 ms
00406 timeOut 200 ms
00406 Level 1 : Two
00407 Level 2 : Two
00407 Level 3 : Two

promise estate make .race and .then:第二级

这是我使用的将来模式:(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))
}

更新: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"]

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