相关文章推荐
犯傻的手链  ·  C# readline: ...·  1 年前    · 
帅气的牛肉面  ·  sql - Error 1046 No ...·  1 年前    · 
想旅行的香烟  ·  YoloX - 知乎·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

    set a property on the promise which can be seen from outside, and use then() to change the property. dandavis Jun 1, 2015 at 0:28 @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); guest271314 Jun 1, 2015 at 1:03 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 JGFMK Aug 14, 2017 at 17:08 Using node v11.12.0 console.log will show promise state. E.G. console.log(Promise.new((resolve, reject) => {}) => Promise { <pending> } Puhlze May 17, 2019 at 16:31

    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.

    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 :) Benjamin Gruenbaum Jun 1, 2015 at 0:30 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?? Tustin2121 May 16, 2016 at 17:53 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? user619271 Dec 4, 2016 at 10:04 @user619271 There are plenty of ways to debug promises. Just because they can't be debugged in the way you want to debug them doesn't make them impractical. I've been working with promises for years and never had a need to synchronously obtain a promise's state. So the claim "we must throw away native promises" is tosh. JLRishe Oct 30, 2017 at 11:52 @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. Benjamin Gruenbaum Aug 10, 2018 at 20:35 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 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. Matthijs Jun 12, 2017 at 7:20 +1 Came here looking for this exactly. Perfect example of an answer not answering the original question, but still being super useful to a lot of people landing here. panepeter Jul 9, 2021 at 9:45

    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;
                    @Klesun maybe this is a good enough solution for more people than just the OP, considering there is an already accepted answer?
    – Isaac
                    Dec 14, 2020 at 21:22
                    But... but there are other questions that don't explicitly deny async solutions, like this one (naturally closed because there is no way a similar sounding problem may actually have different conditions, right, mods ^_^)
    – Klesun
                    Dec 14, 2020 at 22:21
                    solution is very simple without any additional boilerplate code around my promises. so it is not a quite answer to OP but still the best workaround approach.
    – RapidoG
                    Oct 3, 2021 at 11:02
                    it matters just using the pure functions without any artifacts and side mutations on my promises which is pretty good <3
    – Coll
                    Oct 6, 2021 at 18:22
    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

    @MoritzSchmitzv.Hülst a Symbol would be a unique value, therefore you'd never have to guess what "value [...] p should not return." However, a reference to a specific object would work just as well. – Scott Rudiger Oct 13, 2018 at 6:38 Another pitfall I came across while implementing this is that it always loses to any of the composite Promises: Promise.race([Promise.any([Promise.resolve("expected winner")]), Promise.resolve("real winner")]); – cyreb7 Feb 1, 2022 at 2:27

    in node, say undocumented internal process.binding('util').getPromiseDetails(promise)

    > 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> ]
                    i added this because it was not in any of the existing answers, and for node it is the best answer.  it is easy to look up the docs for it in github.com/nodejs/node
    – amara
                    Oct 30, 2017 at 9:24
                    Node 16 code seems to reference a new function, internalBinding, but it doesn't seem to work for me: github.com/nodejs/node/blob/v16.13.1/lib/internal/webstreams/…
    – Dan Jones
                    May 23, 2022 at 19:48
                    You need to pass it a CLI flag. Stop using our internal APIs it makes it super hard to refactor. Instead make the case for why you want us to add a public API and we’ll discuss it and understand each other.
    – Benjamin Gruenbaum
                    Jan 27 at 14:34
    

    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've boiled it down to a polyfill: Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
    – Tustin2121
                    May 16, 2016 at 18:32
                    @JohnWeisz What's horrendous is the lack of backwards compatibility. I'm trying to integrate a promise-ful API to a codebase which assumes everything is synchronous. It's either doing something horrendous or rewriting huge chunks of code. Either way I'm committing an atrocity.
    – rath
                    Aug 3, 2017 at 10:47
                    @Tustin2121 For some version it will fail with something like Promise.resolve('<pending>').
    – user202729
                    Jan 24, 2020 at 8:40
    

    Updated: 2019

    Bluebird.js offers this: http://bluebirdjs.com/docs/api/isfulfilled.html

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

    If you'd prefer to create your own wrapper, here is a nice blog about it.

    Because JavaScript is single-threaded, it's hard to find a common enough use case to justify putting this in the spec. The best place to know if a promise is resolved is in .then(). Testing if a Promise is fullfilled would create a polling loop which is most likely the wrong direction.

    async/await is a nice construct if you'd like to reason async code synchronously.

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

    Another useful call is 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"]
    

    When I first reached for this answer, that is the use case I was looking for.

    It's indeed quite annoying that this basic functionality is missing. If you're using node.js then I know of two workarounds, neither of 'em very pretty. Both snippets below implement the same API:

    > Promise.getInfo( 42 )                         // not a promise
    { status: 'fulfilled', value: 42 }
    > Promise.getInfo( Promise.resolve(42) )        // fulfilled
    { status: 'fulfilled', value: 42 }
    > Promise.getInfo( Promise.reject(42) )         // rejected
    { status: 'rejected', value: 42 }
    > Promise.getInfo( p = new Promise(() => {}) )  // unresolved
    { status: 'pending' }
    > Promise.getInfo( Promise.resolve(p) )         // resolved but pending
    { status: 'pending' }
    

    There doesn't seem to be any way to distinguish the last two promise states using either trick.

    1. Use the V8 debug API

    This is the same trick that util.inspect uses.

    const Debug = require('vm').runInDebugContext('Debug');
    Promise.getInfo = function( arg ) {
        let mirror = Debug.MakeMirror( arg, true );
        if( ! mirror.isPromise() )
            return { status: 'fulfilled', value: arg };
        let status = mirror.status();
        if( status === 'pending' )
            return { status };
        if( status === 'resolved' )  // fix terminology fuck-up
            status = 'fulfilled';
        let value = mirror.promiseValue().value();
        return { status, value };
    

    2. Synchronously run microtasks

    This avoids the debug API, but has some frightening semantics by causing all pending microtasks and process.nextTick callbacks to be run synchronously. It also has the side-effect of preventing the "unhandled promise rejection" error from ever being triggered for the inspected promise.

    Promise.getInfo = function( arg ) {
        const pending = {};
        let status, value;
        Promise.race([ arg, pending ]).then(
            x => { status = 'fulfilled'; value = x; },
            x => { status = 'rejected'; value = x; }
        process._tickCallback();  // run microtasks right now
        if( value === pending )
            return { status: 'pending' };
        return { status, value };
                    It is very unsafe to do process._tickCallback (or even plain %RunMicrotick) - it will randomly break things in your code. I desperately tried getting it to work (for fake timers in async functions, mostly) and it was never stable enough from the Node side. I sort of gave up working on it. The V8 debug mirror API is entirely appropriate here.
    – Benjamin Gruenbaum
                    Aug 10, 2018 at 20:43
                    And.. DeprecationWarning: DebugContext has been deprecated and will be removed in a future version. :( Looks like V8 removed it
    – Benjamin Gruenbaum
                    Aug 10, 2018 at 20:44
                    We (Node) can totally ask V8 for an API or expose an API for looking at a promise's state directly though - if you open an issue at github.com/nodejs/promise-use-cases I will bring it up with V8 happily
    – Benjamin Gruenbaum
                    Aug 10, 2018 at 20:46
                    A comment further down in this topic revealed that an API already appears to exist: process.binding('util').getPromiseDetails( promise ) returns [ 0, ] for pending, [ 1, value ] for fulfilled, and [ 2, value ] for rejected.
    – Matthijs
                    Aug 11, 2018 at 21:39
    

    await usage to @jib's answer, with idiomatic prototyping.

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

    note that this async function execute "almost" immediately like synced function (or actually possibly be instantly).

    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; This would require OP to get access to the promise in a previous turn of the event loop. Since .then always executes asynchronously OP who wants to inspect a promise in the same turn will not get the correct result here. Note OP asked specifically about synchronous inspection and mentioned that they already know about asynchronous inspection. – Benjamin Gruenbaum Jun 1, 2015 at 0:32 @BenjaminGruenbaum: wouldn't the default values come up if code on the same "turn" called it? – dandavis Jun 1, 2015 at 0:33 Of course you'd have to wrap all your promises at creation time. e.g. inside the functions that create and return them. – SpiderPig Jun 1, 2015 at 0:35 Right, at which point they're not really native promises anymore, you might as well extend them the way they're meant to be extended with subclassing which would allow you to do this elegantly instead of monkey patching properties on an object. – Benjamin Gruenbaum Jun 1, 2015 at 0:35 Whether you extend a promise the way I showed or by sub-classing, in each case you'd still have to add your own version of then and catch. – SpiderPig Jun 1, 2015 at 0:38

    I looked through the solutions proposed to this question and could not see one that corresponds to a simple approach that I have used in Node.js.

    I have defined a simple class PromiseMonitor, which takes a promise as the single parameter to its constructor, and has a string property .status which returns the standard string values corresponding to the promise status, "pending", "resolved" or "rejected", and four boolean properties .pending, .resolved, .rejected and .error. The property .error is set true only if .rejected is true and the reject callback was passed an Error object.

    The class simply uses .then() on the promise to change the status of the PromiseMonitor when the promise is resolved or rejected. It does not interfere with any other use of the original promise. Here is the code:

    class PromiseMonitor {
        constructor(prm){
            this._status = "pending";
            this._pending = true;
            this._resolved = false;
            this._rejected = false;
            this._error = false;
                .then( ()=>{  
                            this._status = "resolved"; 
                            this._resolved = true; 
                            this._pending = false; 
                    , (err)=>{ 
                            this._status = "rejected";
                            this._pending = false;
                            this._rejected = true;
                            this._error = err instanceof Error ? true: false ; 
        get status(){ return this._status; };
        get pending(){ return this._pending; };
        get resolved(){ return this._resolved; };
        get rejected(){ return this._rejected; };
        get error(){ return this._error };
    

    To monitor the status of a Promise, simply create an instance of PromiseMonitor, passing the promise in as a parameter, for example:

    let promiseObject = functionThatReturnsAPromise();
    let promiseMonitor = new PromiseMonitor( promiseObject );
    

    Now you can syncrhonously check all the properties of promiseMonitor, which will track the status of the original promise. Here is a test script that demonstrates the three possible resolutions of a promise being monitored.

    let ticks = 0;
    let tickerID = setInterval( ()=>{++ticks; console.log(`..tick ${ticks}`)}, 1000);
    async function run(){
        console.log("Start");
        let delay = prmDelay(2000);
        let delayMonitor = new PromiseMonitor(delay);
        // normal handling of delay promise
        delay.then((result)=>( console.log("Normal resolution of delay using .then()") ) );
        console.log("delay at start:\n", delay);
        console.log("delayMonitor at start:\n", delayMonitor);
        await delay;
        console.log("delay finished:\n", delay);
        console.log("delayMonitor finished:\n", delayMonitor);
        console.log("\n\n TEST2: Rejection without an Error test ================================")
        let rejDelay = prmDelay(3000, "reject");
        let rejMonitor = new PromiseMonitor(rejDelay);
        // normal handling of reject result on promise
        rejDelay.then((result)=>( console.log("Normal resolution of rejDelay using .then will not happen") ) 
                        , (err)=>( console.log("Rejection of rejDelay handled using .then")));
        console.log("rejDelay at start:\n", rejDelay);
        console.log("rejMonitor at start:\n", rejMonitor);
        await rejDelay.catch( (err)=>{ console.log( "Caught error using .catch on rejDelay" ); });
        console.log("rejDelay finished:\n", rejDelay);
        console.log("rejMonitor finished:\n", rejMonitor);
        console.log("\n\n TEST3: Rejection with an Error test ================================")
        let errMonitor ;
        let errDelay;
            errDelay = prmDelay(1000, "error");
            errMonitor = new PromiseMonitor(errDelay);
            // normal handling of results of the original promise
            errDelay.then(
                (result)=>{ 
                    console.log("Normal expiry of errDelay");
                    console.log("Monitor Status is " + errMonitor.status )
                , (err)=>{
                    console.log("** Rejection of errDelay handled using .then()");
                    console.log("   Monitor Status is " + errMonitor.status )
            console.log("errDelay at start:\n", errDelay);
            console.log("errMonitor at start:\n", errMonitor);
            await errDelay;
            console.log("**** This should never be run");
        } catch(err) { 
            console.log( "** Caught error on errDelay using try{}catch{}:" ); 
            console.log( "   Monitor Status is " + errMonitor.status )
        console.log("errDelay finished:\n", errDelay);
        console.log("errMonitor finished:\n", errMonitor);
        clearInterval(tickerID);
     * Creates a new promise with a specific result
     * @param {*} tt 
     * @param {*} exitType ("resolve", "reject" or "error")
    function prmDelay (tt, exitType) {
        return new Promise(function(resolve, reject) {
            if( exitType == 'reject' ){
                setTimeout(()=>{ reject("REJECTED")}, tt);
            } else if( exitType== 'error'){
                setTimeout(()=>{ reject(new Error( "ERROR Rejection") ); }, tt);
            } else {
                setTimeout(()=>{ resolve("RESOLVED") }, tt);
    run();
    

    You can add a method to Promise.prototype. It looks like this:

    Edited: The first solution is not working properly, like most of the answers here. It returns "pending" until the asynchronous function ".then" is invoked, which is not happen immediately. (The same is about solutions using Promise.race). My second solution solves this problem.

    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;
    

    You can use it on any Promise. For exemple:

    myPromise = new Promise(myFunction);
    console.log(myPromise.getState()); // pending|resolved|rejected
    

    Second (and correct) solution:

    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";
                            state = "resolved";
                        pending = false;
                function rej(e) {
                    reject(e);
                    if (pending) {
                        if (newPromise)
                            newPromise.state = "rejected";
                            state = "rejected";
                        pending = false;
    

    And use it:

    Notice: In this solution you doesn't have to use the "new" operator.

    myPromise = Promise.stateable(myFunction);
    console.log(myPromise.state); // pending|resolved|rejected
    

    Caveat: This method uses undocumented Node.js internals and could be changed without warning.

    In Node you can synchronously determine a promise's state using process.binding('util').getPromiseDetails(/* promise */);.

    This will return:

    [0, ] for pending,

    [1, /* value */] for fulfilled, or

    [2, /* value */] for rejected.

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

    Wrapping this into a helper function:

    const getStatus = promise => ['pending', 'fulfilled', 'rejected'][
      process.binding('util').getPromiseDetails(promise)[0]
    getStatus(pending); // pending
    getStatus(fulfilled); // fulfilled
    getStatus(rejected); // rejected
                    Doesn't seem to work from within jest (which is the only place I'm interested in it, really).  The function exists, but always seems to return undefined.  How do I find out what's wrong?
    – Adam Barnes
                    May 15, 2019 at 11:57
                    Hmm, I remember it working within mocha; never tried it with jest though. Maybe start a new question linking here and include your Node.js version as well as jest version?
    – Scott Rudiger
                    May 16, 2019 at 14:56
                    Not something I'm interested in a great deal any more, unfortunately.  I was basically looking to sanity test my manually-resolvable/rejectable Promise that I was only using to test stuff that should be going on while a Promise is pending, but I figured so long as what I wrote, works, then there's no need to test that in addition to what relies on it.
    – Adam Barnes
                    May 16, 2019 at 15:35
    

    There's another elegant & hacky way of checking if a promise is still pending just by converting the whole object to string and check it with the help of inspect like this: util.inspect(myPromise).includes("pending").

    Tested on Node.js 8,9,10,11,12,13

    Here's a full example

    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)
    

    Result:

    false false false This is an interesting hack, but keep in mind that util.inspect is intended for debugging and it should not be heavily relied upon, since it's output may change at any time. – Leonardo Raele Dec 11, 2020 at 13:06

    what you can do, is to use a variable to store the state, manually set the state to that variable, and check that variable.

    var state = 'pending';
    new Promise(function(ff, rjc) {
      //do something async
      if () {//if success
        state = 'resolved';
        ff();//
      } else {
        state = 'rejected';
        rjc();
    console.log(state);//check the state somewhere else in the code
    

    of course, this means you must have access to the original code of the promise. If you don't, then you can do:

    var state = 'pending';
    //you can't access somePromise's code
    somePromise.then(function(){
      state = 'resolved';
    }, function() {
      state = 'rejected';
    console.log(state);//check the promise's state somewhere else in the code
    

    My solution is more coding, but I think you probably wouldn't have to do this for every promise you use.

    The simplest answer; I was going to post something like this, I'm glad it was already here. – Jason C Apr 17, 2022 at 18:30 Btw: I like to use constructs like this when I'm doing it synchronously: let result = await somePromise.then(v=>{ok:v}, e=>{failed:e});, then the status and value/error is left in result. – Jason C Apr 17, 2022 at 18:36

    I made a package for this. Unlike most of the other answers here, it doesn't swallow unhandled rejections.

    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'
    

    It looks like somehow nobody came up with one of the simplest solution that doesn't require any hacks:

  • define a variable to indicate that the promise is running
  • Add a .finally clause to the promise that sets the variable to false (you can do it at any time after the promise is created)
  • After that in your code just check if the above variable is true or false, to see whether the Promise is still running.
  • If you want to know not just whether it's finished or not then instead of .finally add a .then and a .catch clauses that set the variable to "resolved" or "rejected".

    The only drawback is that the state variable doesn't get set right away (synchronously) when you add the clauses, in case the promise has already finished. Because of this, it's best to add this to the earliest possible place after the creation of the promise.

    Example:

    async function worker(){
      // wait a very short period of time
      await (new Promise(resolve => setTimeout(resolve, 100)))
      //...
    const w1=worker()
    let w1_running=true
    w1.finally( ()=> {w1_running=false});
    //...
    //Then check if it's running
    (async ()=>{
      while(true){
        if (w1_running) {
          console.log("Still Busy :(")
        } else {
          console.log("All done :)")
          break
        await (new Promise(resolve => setTimeout(resolve, 10)))
    // Note we need some async action started otherwise the event loop would never reach the code in the function `worker` or in the `.finally` clause
                    Re "add a .then and a .catch clause": You can just use a .then for that; the second parameter is a rejection callback and behaves like .catch, e.g.: .then(v => /* resolved with v */, e => /* rejected with e */). I like to use constructs like this when I'm doing it synchronously: let result = await someArbitraryPromise.then(v => { ok: v }, e => { failed: e });, then the status is left in result.
    – Jason C
                    Apr 17, 2022 at 18:35
                    By far the most non-performant answer, do not use if you care about a well-styled and performant application
    – Gabriel Petersson
                    Sep 12, 2022 at 12:49
    
    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>

    2019:

    The simple way to do that as I know is thenable , super thin wrapper around promise or any async job.

    const sleep = (t) => new Promise(res => setTimeout(res,t));
    const sleeping = sleep(30);
    function track(promise){
        let state = 'pending';
        promise = promise.finally( _=> state ='fulfilled');
        return {
            get state(){return state},
            then: promise.then.bind(promise), /*thentable*/
            finally:promise.finally.bind(promise),
            catch:promise.catch.bind(promise),
    promise = track(sleeping);
    console.log(promise.state) // pending
    promise.then(function(){
        console.log(promise.state); // fulfilled
    

    You can create your own subclass, say QueryablePromise, by inheriting from the natively available Promise class, the instances of which would have a status property available on it that you can use to query the status of the promise objects synchronously. An implementation of it can be seen below or refer this for a better explanation.

    class QueryablePromise extends Promise {
      constructor (executor) {
        super((resolve, reject) => executor(
          data => {
            resolve(data)
            this._status = 'Resolved'
          err => {
            reject(err)
            this._status = 'Rejected'
        this._status = 'Pending'
      get status () {
        return this._status
    // Create a promise that resolves after 5 sec 
    var myQueryablePromise = new QueryablePromise((resolve, reject) => {
      setTimeout(() => resolve(), 5000)
    // Log the status of the above promise every 500ms
    setInterval(() => {
      console.log(myQueryablePromise.status)
    }, 500)
    Unfortunately, no existing API will return this new class. How are you imagining people use this? – jib Dec 27, 2019 at 2:08 No existing APIs will return it, because they would have to be written to return it, right? E.g. if I call fetch it will return a native promise. How would your class help with that? – jib Dec 27, 2019 at 15:21 Well, can't we just wrap that fetch call in our new QuerablePromise like: const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) }) ? Or, is there an issue with that? :/ – UtkarshPramodGupta Dec 27, 2019 at 15:52 That should work, just don't forget , err => reject(err) as a second arg to then or it won't propagate errors correctly (among the reasons it's considered the promise constructor anti-pattern). It's not truly synchronous though (e.g. won't detect an already-resolved promise), but perhaps useful in cases where you don't control the caller and the answer is needed immediately. – jib Dec 27, 2019 at 16:27

    CAVEAT: process.binding('util').getPromiseDetails is undefined on node 16!

    Benchmark:

    Candidates:

    * 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)

    Test promises:

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

    Run benchmark:

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

    Result:

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

    Obviously isPromisePending1() is too faster (8~10 times)! But it's not usable on node 16! (see above caveat).

    If you're using ES7 experimental you can use async to easily wrap the promise you want to listen.

    async function getClient() {
      let client, resolved = false;
      try {
        client = await new Promise((resolve, reject) => {
          let client = new Client();
          let timer = setTimeout(() => {
             reject(new Error(`timeout`, 1000));
             client.close();
          client.on('ready', () => {
            if(!resolved) {
              clearTimeout(timer);
              resolve(client);
          client.on('error', (error) => {
            if(!resolved) {
              clearTimeout(timer);
              reject(error);
          client.on('close', (hadError) => {
            if(!resolved && !hadError) {
              clearTimeout(timer);
              reject(new Error("close"));
        resolved = true;
      } catch(error) {
        resolved = true;
        throw error;
      return client;
    

    I've written a little npm package, promise-value, which provides a promise wrapper with a resolved flag:

    https://www.npmjs.com/package/promise-value

    It also gives synchronous access to the promise value (or error). This doesn't alter the Promise object itself, following the wrap rather than extend pattern.

    This is older question but I was trying to do something similar. I need to keep n workers going. They are structured in a promise. I need to scan and see if they are resolved, rejected or still pending. If resolved, I need the value, if rejected do something to correct the issue or pending. If resolved or rejected I need to start another task to keep n going. I can't figure a way to do it with Promise.all or Promise.race as I keep working promises in an array and can find no way to delete them. So I create a worker that does the trick

    I need a promise generator function that returns a promise which resolves or rejects as necessary. It is called by a function that sets up the framework to know what the promise is doing.

    In the code below the generator simply returns a promise based on setTimeout.

    Here it is

    //argObj should be of form
    // {succeed: <true or false, nTimer: <desired time out>}
    function promiseGenerator(argsObj) {
      let succeed = argsObj.succeed;          
      let nTimer = argsObj.nTimer;
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (succeed) {
            resolve('ok');
          else {
            reject(`fail`);
        }, nTimer);
    function doWork(generatorargs) {
      let sp = { state: `pending`, value: ``, promise: "" };
      let p1 = promiseGenerator(generatorargs)
        .then((value) => {
          sp.state = "resolved";
          sp.value = value;
        .catch((err) => {
          sp.state = "rejected";
          sp.value = err;
      sp.promise = p1;
      return sp;
    

    doWork returns an object containing the promise and the its state and returned value.

    The following code runs a loop that tests the state and creates new workers to keep it at 3 running workers.

    let promiseArray = [];
    promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
    promiseArray.push(doWork({ succeed: true, nTimer: 500 }));
    promiseArray.push(doWork({ succeed: false, nTimer: 3000 }));
    function loopTimerPromise(delay) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('ok');
        }, delay)
    async function looper() {
      let nPromises = 3;      //just for breaking loop
      let nloop = 0;          //just for breaking loop
      let i;
      //let continueLoop = true;
      while (true) {
        await loopTimerPromise(900);  //execute loop every 900ms
        nloop++;
        //console.log(`promiseArray.length = ${promiseArray.length}`);
        for (i = promiseArray.length; i--; i > -1) {
          console.log(`index ${i} state: ${promiseArray[i].state}`);
          switch (promiseArray[i].state) {
            case "pending":
              break;
            case "resolved":
              nPromises++;
              promiseArray.splice(i, 1);
              promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
              break;
            case "rejected":
              //take recovery action
              nPromises++;
              promiseArray.splice(i, 1);
              promiseArray.push(doWork({ succeed: false, nTimer: 500 }));
              break;
            default:
              console.log(`error bad state in i=${i} state:${promiseArray[i].state} `)
              break;
        console.log(``);
        if (nloop > 10 || nPromises > 10) {
          //should do a Promise.all on remaining promises to clean them up but not for test
          break;
    looper();
    

    Tested in node.js

    BTW Not in this answer so much but in others on similar topics, I HATE it when someone says "you don't understand" or "that's not how it works" I generally assume the questioner knows what they want. Suggesting a better way is great. A patient explanation of how promises work would also be good.

    Old question with many answers but none seem to suggest what I think is the simplest solution: set a bool indicator on promise resolution/rejection.

    class Promise2 {
      constructor(...args) {
        let promise = new Promise(...args);
        promise.then(() => promise._resolved_ = true);
        promise.catch(() => promise._rejected_ = true);
        return promise;
    let p = new Promise2(r => setTimeout(r, 3000));
    setInterval(() => {
      console.log('checking synchronously if p is resolved yet?', p._resolved_);
    }, 1000);
    That's not a valid answer because it implies you have access to the implementation of the Promise callback, which is likely not the case otherwise, yes, it would be as simple as setting a flag. – Leonardo Raele Dec 11, 2020 at 13:02

    This is the Future pattern I use: (https://github.com/Smallscript-Corp)

  • enables sync and async fn usage
  • enables event patterns to be unified with async behavior
  • 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
    

    Then you can create future-value instances that can be resolved using sync and async functions; enables handling events uniformly.

    You can use it to write a pattern like:

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

    If you want to create your own observable promises (OP class) then this functionality is rather simple. Plus you can even prematuraly resolve or reject it externally because I expose the resolve and reject functions as well. This means you can abort a promise whenever you want by calling it's .reject(e) method. Obviously this is not inline with the Promise specificiations A+. Yet, while we don't extend the Promise class, as a draft it should still be compatible with the native promises and async-await. Since this eliminates the well thought precautions of async operations, you should be careful when using abstractions like this one.

    I have also added some extra functionalities like wait and log to show how easy it would be to chain up custom async tasks in a sane manner.

    class OP {
      static resolve = r => new OP(v => v(r));
      static reject  = e => new OP((_,x) => x(e));
      constructor(cb) {
        this.#p = new Promise((v,x) => ( this.#v = v
                                       , this.#x = x
                                       , cb && cb( r => this.resolve(r)
                                                 , e => this.reject(e)
        this.#s = "pending";
        this.#r;
      get status(){
        return this.#s;
      get result(){
        return this.#r;
      resolve(r){
        this.#v(r);
        this.#s === "pending" && ( this.#s = "resolved"
                                 , this.#r = r
      reject(e){
        this.#x(e);
        this.#s === "pending" && ( this.#s = "rejected"
                                 , this.#r = e
      then(onFulfilled,onRejected){
        return new OP((v,x) => this.#p.then( r => v(onFulfilled ? onFulfilled(r) : r)
                                            , e => v(onRejected ? onRejected(e) : e)
      catch(onRejected){
        return new OP((v,x) => this.#p.catch(e => v(onRejected ? onRejected(e) : e)));
      finally(onFinally){
        return new OP((v,x) => this.#p.finally(_ => v(onFinally ? onFinally() : void 0)));
      wait(ms){
          return this.then(r => new OP((v,x) => setTimeout(v,ms,r)))
      log(str){
          return this.then(r => (console.log(str ? str : r),r));
    var p = new OP((v,x) => setTimeout(v,1000,"OP works..!")),
        q = new OP((v,x) => setTimeout(v,2000,"OP works also with Promise methods..!"));
    setTimeout(_ => console.log(p.status),500);
    setTimeout(_ => console.log(p.status),1500);
    p.then(str => console.log(str))
     .catch(err => console.log(err));
    Promise.all([p,q]).then(rs => rs.forEach(r => console.log(r)));
    p.then(str => (console.log(str),str)).then(str => console.log("once again",str));
    async function tester(){
      if (Math.random() < 0.5) return await OP.reject("oops the async function threw..!");
      return await new OP((v,x) => setTimeout(v,3000,"OP works with await..!"));
    tester().then(s => console.log(s)).catch(e => console.log(e));
    OP.resolve()
      .wait(4000)
      .log("Hello")
      .wait(1000)
      .log("there")
      .wait(1000)
      .log("something useful..!");

    I found this solution to be simple and allow me to continue using native promises but add useful synchronous checks. I also didn't have to pull in an entire promise library.

    CAVEAT: This only works if there is some sort of break in the current execution thread to allow the promises to execute BEFORE checking the synchronous constructs. That makes this of more limited usefulness than I'd initially thought -- still useful for my use case though (Thanks Benjamin Gruenbaum for pointing this out)

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

    From https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved which based their answer on Is there a way to tell if an ES6 promise is fulfilled/rejected/resolved?

    As added in your comment on my answer - this is entirely incorrect: that 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. – Benjamin Gruenbaum Aug 10, 2018 at 20:40 I see what you're saying and you make a good point. The single threaded nature of JS is getting in the way isn't it? You have to put a break in the current execution for the promise to be marked as resolved. let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1); Which as long as you do that, this works nicely. But you have to understand that fact for this to be useful. I'll update the description with that caveat. I also agree that the function naming could be better/more idiomatic. – Akrikos Aug 21, 2018 at 22:17 But at that point you could just then the original promise and accomplish the same thing since it's asynchronous anyway. There is a way with process.binding('util').getPromiseDetails that does seem to work but it's using a private API – Benjamin Gruenbaum Aug 21, 2018 at 22:19 It's obnoxious to have to then all the time and makes the code much more difficult to understand. Especially when all I care about is if the promise has been rejected or not -- so my options are to either store that state somewhere else or do something like this. I admit I didn't read the other solutions here thoroughly before posting my own -- apologies for that. This problem is stickier than I'd at first thought. – Akrikos Aug 21, 2018 at 22:28

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.