Search code examples
javascriptnode.jsecmascript-6google-chrome-devtoolses6-promise

How to find where promise was created?


I posted this question a couple of days ago, then removed it after I was pointed that it essentially didn't demonstrate the problem I was dealing with. Then I was asked to restore the question, but I still have to modify it to clearly show the issue I had.


With JavaScript promises, in its 'resolved handler' how to find (if possible at all) where this particular promise was created?

E.g. in this situation, with this code (with async/await there seems to be no difference) when the code execution is stopped on the debugger statement, how to see where the corresponding promise was created:

'use strict';

const promise = getPromise();
handleResolution(promise);

function handleResolution(promiseArg) {
  promiseArg
  .then((resolution) => {
    debugger;
    console.log(`resolved with: ${ resolution }`);
  });
}

function getPromise() {
  return new Promise((resolve) => {
      resolve('in getPromise()');
  });
}

Hardly the call stack can be used here, because it's obvious that the call stack where a particular asynchronous call was done is long gone.

example code paused in chrome dev-tools debugger

Is there something like a way to see a 'promise chain' sort of?

The question is about JS in general, not necessarily Node.js, Chrome dev tools etc. It just happened that I used this stack for this example.


Solution

  • No, this is not generally possible.

    For an asynchronous resolution handler, there's three "call stack states" that might be of interest:

    • the one where the promise was created: new Promise()
    • the one where the handler was attached: .then()
    • the one where the promise was settled: resolve()

    Only the second one is available in your dev tools as the async call stack, visible also in your screenshot. This also matches the async stack trace that you'd get when using await, where it is literally the stack of suspended functions waiting to be resumed, which makes this choice more efficient.

    Usually this is also the most interesting and useful one. The place (function call, getPromise() in your example) where the promise was created is normally not far away, and if you really need to, you can place a breakpoint there to step into the promise creation, which should also lead you to the code that resolves the promise (inside the executor, resolve('in getPromise') in your example).

    Retaining the stack traces also for the other two cases is more expensive (memory-wise), and given that they form some sort of tree structure not a simple linked list, also would be challenging to display in the devtools UI in a understandable format.