How can I synchronously determine a JavaScript Promise's state?

I have a pure JavaScript Promise (built-in implementation or poly-fill):

var promise = new Promise(function (resolve, reject) { /* ... */ });

From the specification, a Promise can be one of:

  • 'settled' and 'resolved'
  • 'settled' and 'rejected'
  • 'pending'

I have a use case where I wish to interrogate the Promise synchronously and determine:

  • is the Promise settled?

  • if so, is the Promise resolved?

I know that I can use #then() to schedule work to be performed asynchronously after the Promise changes state. I am NOT asking how to do this.

This question is specifically about synchronous interrogation of a Promise's state. How can I achieve this?

No such synchronous inspection API exists for native JavaScript promises. It is impossible to do this with native promises. The specification does not specify such a method.

Userland libraries can do this, and if you're targeting a specific engine (like v8) and have access to platform code (that is, you can write code in core) then you can use specific tools (like private symbols) to achieve this. That's super specific though and not in userland.

I know that I can use #then(). Then will not tell us the actual state of the promise. But it will wait until the promise will be resolved. And if by synchronously you just mean to get the actual status with no waiting till the Promise will be resolved (which actually may even never happen) there’s an utility promise-status-async which is not a sync but does such a trick

promise-status-async does the trick. It is async but it does not use then to wait the promise to be resolved.

const {promiseStatus} = require('promise-status-async');
// ...
if (await promiseStatus(promise) === 'pending') {
    const idle = new Promise(function(resolve) {
        // can do some IDLE job meanwhile
    });
    return idle;
}

I can track the state of the Promise using additional variables (as others have suggested), but those state values already exist somewhere private per the functioning of a Promise. I'd be duplicating work that the JavaScript engine is already performing internally, at the risk of introducing errors in my code.

Nope, no sync API, but here's my version of the async promiseState (with help from @Matthijs):

function promiseState(p) {
  const t = {};
  return Promise.race([p, t])
    .then(v => (v === t)? "pending" : "fulfilled", () => "rejected");
}

var a = Promise.resolve();
var b = Promise.reject();
var c = new Promise(() => {});

promiseState(a).then(state => console.log(state)); // fulfilled
promiseState(b).then(state => console.log(state)); // rejected
promiseState(c).then(state => console.log(state)); // pending

A Javascript Promise is a value that can be returned that will be filled in or completed at some future time. Most libraries can be wrapped with a Promise interface, and many implement Promises natively. In the code here we're using the request-promise library, which wraps the standard HTTP request library with a Promise interface.

You can make a race with Promise.resolve It's not synchronous but happens now

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

A little script for testing and understand their meaning of asynchronously

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');

results with delay(0) (comment the while in delay)

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

and the results of this test with firefox(chrome keep the order)

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

promiseState make .race and .then : Level 2

To avoid surprises, functions passed to then() will never be called synchronously, even with an already-resolved promise: Promise.resolve().then(() => console.log(2)); console.log(1); // 1, 2 Instead of running immediately, the passed-in function is put on a microtask queue, which means it runs later when the queue is emptied at the end of the current run of the JavaScript event loop, i.e. pretty soon:

You can use an (ugly) hack in Node.js until a native method is offered:

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
}

I am writing a test helper function which returns a promise with a precalculated value. So i call return Promise.resolve(someValue); Is there a way i can force this to resolve synchronously such that

For example, of the promise is exposed out of the function, having the property available on the promise is nicer. – Amit Mar 29 '16 at 21:14 Sure, but usually nobody expects to use such a property on a promise, so there's no need to expose it.

The async function itself returns a promise so you can use that as a promise with chaining like I do above or within another async await function. The function above would wait for each response before sending another request if you would like to send the requests concurrently you can use Promise.all.

I'm used to Dojo promises, where I can just do the following: promise.isFulfilled(); promise.isResolved(); promise.isRejected(); Is there a way to determine if an ES6 promise is fulfilled, resolv

Comments
  • set a property on the promise which can be seen from outside, and use then() to change the property.
  • @jokeyrhyme fwiw, v8 source code.google.com/p/v8/source/browse/branches/bleeding_edge/src/… see var promiseStatus = NEW_PRIVATE("Promise#status"); , PromiseSet function at SET_PRIVATE(promise, promiseStatus, status);
  • Here we go: esdiscuss.org/topic/…
  • It seems odd that if you do const a = Promise.resolve('baz'); console.log(a); and look in Chrome console, you see Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "baz"} proto : Promise [[PromiseStatus]] : "resolved" [[PromiseValue]] : "baz" and people claim it can't be done. How is Chrome doing it? (was doing this in a Plunker with Angular plnkr.co/edit/IPIWgLJKQStI5ubXmcsF
  • Using node v11.12.0 console.log will show promise state. E.G. console.log(Promise.new((resolve, reject) => {}) => Promise { <pending> }
  • Note: I honestly believe the use cases for synchronous inspection are few and very rare, if you share your concrete use case in a new question asking how to achieve it without synchronous inspection - I'll give answering it a shot if someone won't beat me to it :)
  • Even if the use cases are rare, what harm would including something like this do? I would need a status check like this to see if the previous job was finished and if I can request another job. And I can't just set an external variable because the object has the potential to change owners without notice. What's more irritating is I can SEE Node.js has access to this information because it shows it to me when I inspect it, but there's no way to get at it besides parsing strings??
  • So we must throw away native promises as they're impractical and always use bluebird. Great news! How do I propose native promises to become deprecated and thrown out of node engine?
  • Lots of things, we should have specced .any instead and made a mistake because Mark insisted. For one, Promise.race([]) is a forever pending promise (and not an error), you typically want the first successful promise and not just the first promise. Anyway, that's not really relevant to the question asked - OP asked about synchronous inspection and not about .race and its many shortcomings.
  • @Akrikos that answer does't let you synchronously inspect the state of a promise - For example MakeQueryablePromise(Promise.resolve(3)).isResolved is false but the promise is quite obviously resolved. Not to mention that answer is also using the term "resolved" and "fulfilled" incorrectly. To do that that answer does you could just add a .then handler yourself - which completely misses the point of synchronous inspection.
  • OP asked about how to do it synchronously though
  • Is there a specific reasoning behind this construction? It seems unnecessarily complicated to me. As far as I can tell this works identically: Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]); Although this seems safer to me: const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected") and avoids creating additional promises that persist as long as the original p is pending.
  • Thanks @Matthijs! I've simplified my answer.