Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The dreaded "throwing after await" #34

Open
fasterthanlime opened this issue Jun 19, 2017 · 19 comments
Open

The dreaded "throwing after await" #34

fasterthanlime opened this issue Jun 19, 2017 · 19 comments

Comments

@fasterthanlime
Copy link

This might be completely expected, I'm not completely up-to-date on the state of node.js, but:

Repro steps

git clone https://github.com/fasterthanlime/async-test && cd async-test
npm i
npm start

Versions

$ node --version
v8.0.0

$ npm list
[email protected] C:\msys64\home\amwenger\Dev\async-test
`-- [email protected]
  `-- [email protected]

Output

=================================
 Throwing first thing
=================================
Full stack trace:
Error: throwing first thing
    at cherrypie (C:\msys64\home\amwenger\Dev\async-test\index.js:12:13)
    at binomial (C:\msys64\home\amwenger\Dev\async-test\index.js:14:40)
    at abacus (C:\msys64\home\amwenger\Dev\async-test\index.js:15:38)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:16:22)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\async-test\index.js:34:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at <anonymous>
    at checkStack (C:\msys64\home\amwenger\Dev\async-test\index.js:38:5)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:16:11)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\async-test\index.js:34:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3


=================================
 Throwing after await
=================================
Full stack trace:
Error: after timeout
    at cherrypie (C:\msys64\home\amwenger\Dev\async-test\index.js:26:13)
    at <anonymous>
    at <anonymous>
    at checkStack (C:\msys64\home\amwenger\Dev\async-test\index.js:38:5)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:30:11)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3


didn't see abacus, bailing

Expected output

In the second trace, something like:

<snip>
Error: after timeout
    at cherrypie (C:\msys64\home\amwenger\Dev\async-test\index.js:26:13)
    at binomial (path:line)
    at abacus (path:line)
<snip>
@fasterthanlime
Copy link
Author

N.B: turning

const binomial = async () => await cherrypie();

into

async function binomial () { await cherrypie(); }

appears to make no difference whatsoever.

@AndreasMadsen
Copy link
Owner

@fasterthanlime Thanks, that does look suspicious. I will look at it next week after I have handed in my master thesis. In the meantime, I recommend upgrading to node v8.1.x where we landed some changes to how promises show up in async_hooks and thus also trace (nodejs/node#13367).

@fasterthanlime
Copy link
Author

Cool, thanks!

Here's the output with node v8.1.2:

=================================
 Throwing first thing
=================================
Full stack trace:
Error: throwing first thing
    at cherrypie (C:\msys64\home\amwenger\Dev\async-test\index.js:12:13)
    at binomial (C:\msys64\home\amwenger\Dev\async-test\index.js:14:40)
    at abacus (C:\msys64\home\amwenger\Dev\async-test\index.js:15:38)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:16:22)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\async-test\index.js:34:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at <anonymous>
    at checkStack (C:\msys64\home\amwenger\Dev\async-test\index.js:38:5)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:16:11)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\async-test\index.js:34:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at <anonymous>
    at checkStack (C:\msys64\home\amwenger\Dev\async-test\index.js:38:5)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:16:11)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\async-test\index.js:34:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3


=================================
 Throwing after await
=================================
Full stack trace:
Error: after timeout
    at cherrypie (C:\msys64\home\amwenger\Dev\async-test\index.js:26:13)
    at <anonymous>
    at <anonymous>
    at checkStack (C:\msys64\home\amwenger\Dev\async-test\index.js:38:5)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:30:11)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at <anonymous>
    at checkStack (C:\msys64\home\amwenger\Dev\async-test\index.js:38:5)
    at main (C:\msys64\home\amwenger\Dev\async-test\index.js:30:11)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

@AndreasMadsen
Copy link
Owner

Thanks, I didn't really expect the upgrade to fix it.

It looks like there is another bug, at bootstrap_node.js:575:3 should never occur more than once per trace. I did suspect this bug existed but I could never create it. This is awesome, thanks.

@fasterthanlime
Copy link
Author

Happy to help!

I have a whole suite of tests like that, because I was tired of getting useless stack traces in my error reports: https://github.com/itchio/itch/blob/cead3ba6bcbe5c46f57dc6b95b01763e73a87420/src/confidence/stacktrace.spec.ts

My current solution is using babel to transpile all Promise code to bluebird, and enable bluebird's longStackTraces collection. Which works well enough, but I feel like native v8 promises + async_hooks should be faster, since bluebird Promises are coroutine-based.

There's literally 0 time pressure on this though - before I can switch to native promises + async_hooks, electron has to release with node v8.0.0, and that'll probably take a few weeks!

@AndreasMadsen
Copy link
Owner

AndreasMadsen commented Jun 26, 2017

Your "Throwing first thing" creates 13 Promise instances, I'm having some trouble identifying them all. Could you demonstrate the issue where async/await is ported to the new Promise(), .then(), and .catch() API.

edit: I have pushed a new master that removes some of the at bootstrap_node.js:575:3 duplicates. Not all of them can be removed (or should be removed) as some of them are due to how node.js executes the microtask queue in combination with nextTick.

@fasterthanlime
Copy link
Author

Your "Throwing first thing" creates 13 Promise instances, I'm having some trouble identifying them all. Could you demonstrate the issue where async/await is ported to the new Promise(), .then(), and .catch() API.

Interesting, the issue doesn't seem to appear with pure promises

$ npm start

> [email protected] start C:\msys64\home\amwenger\Dev\promise-test
> node --stack_trace_limit=100 index.js

=================================
 Throwing first thing
=================================
Full stack trace:
Error: throwing first thing
    at Promise (C:\msys64\home\amwenger\Dev\promise-test\index.js:11:12)
    at Promise (<anonymous>)
    at cherrypie (C:\msys64\home\amwenger\Dev\promise-test\index.js:10:27)
    at binomial (C:\msys64\home\amwenger\Dev\promise-test\index.js:13:26)
    at abacus (C:\msys64\home\amwenger\Dev\promise-test\index.js:14:24)
    at firstThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:15:21)
    at main (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:3)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\promise-test\index.js:37:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at Promise.catch (<anonymous>)
    at checkStack (C:\msys64\home\amwenger\Dev\promise-test\index.js:43:11)
    at firstThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:15:10)
    at main (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:3)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\promise-test\index.js:37:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at Promise.then (<anonymous>)
    at checkStack (C:\msys64\home\amwenger\Dev\promise-test\index.js:40:18)
    at firstThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:15:10)
    at main (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:3)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\promise-test\index.js:37:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at Promise (<anonymous>)
    at cherrypie (C:\msys64\home\amwenger\Dev\promise-test\index.js:10:27)
    at binomial (C:\msys64\home\amwenger\Dev\promise-test\index.js:13:26)
    at abacus (C:\msys64\home\amwenger\Dev\promise-test\index.js:14:24)
    at firstThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:15:21)
    at main (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:3)
    at Object.<anonymous> (C:\msys64\home\amwenger\Dev\promise-test\index.js:37:1)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

=================================
 Throwing after await
=================================
Full stack trace:
Error: after timeout
    at Promise.then (C:\msys64\home\amwenger\Dev\promise-test\index.js:26:13)
    at <anonymous>
    at Promise.catch (<anonymous>)
    at checkStack (C:\msys64\home\amwenger\Dev\promise-test\index.js:43:11)
    at secondThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:30:10)
    at firstThing.then (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:27)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at Promise.then (<anonymous>)
    at checkStack (C:\msys64\home\amwenger\Dev\promise-test\index.js:40:18)
    at secondThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:30:10)
    at firstThing.then (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:27)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at Promise.then (<anonymous>)
    at cherrypie (C:\msys64\home\amwenger\Dev\promise-test\index.js:25:6)
    at binomial (C:\msys64\home\amwenger\Dev\promise-test\index.js:28:26)
    at abacus (C:\msys64\home\amwenger\Dev\promise-test\index.js:29:24)
    at secondThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:30:21)
    at firstThing.then (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:27)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3
    at Promise (<anonymous>)
    at cherrypie (C:\msys64\home\amwenger\Dev\promise-test\index.js:24:5)
    at binomial (C:\msys64\home\amwenger\Dev\promise-test\index.js:28:26)
    at abacus (C:\msys64\home\amwenger\Dev\promise-test\index.js:29:24)
    at secondThing (C:\msys64\home\amwenger\Dev\promise-test\index.js:30:21)
    at firstThing.then (C:\msys64\home\amwenger\Dev\promise-test\index.js:34:27)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:86:5)
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

@AndreasMadsen
Copy link
Owner

@fasterthanlime Well I'm no expert in async/await, but I'm pretty sure you can't just remove the async and await statements.

(async () => {})() corresponds to new Promise( () => {}) and await promise; corresponds to .then(() => promise), or something like that.

@fasterthanlime
Copy link
Author

fasterthanlime commented Jun 26, 2017

@fasterthanlime Well I'm no expert in async/await, but I'm pretty sure you can't just remove the async and await statements.

(async () => {})() corresponds to new Promise( () => {}) and await promise; corresponds to .then(() => promise), or something like that.

That's what I did though :)

 const cherrypie = () =>
    new Promise((resolve, reject) => setTimeout(resolve, 200))
    .then(() => {
      throw new Error(`after timeout`);
    })

These all behave the same:

// relay the original promise
const v1 = () => functionReturningPromise();

// wrap the original promise - if it resolves the wrapper
// will resolve, if it rejects the wrapper will reject
const v2 = () => Promise.resolve(functionReturningPromise());

// async functions "rethrow" rejections and can "return"
// resolved values asynchronously
const v3 = async () => await functionReturningPromise();

// don't write that ;)
const v4 = () => {
  return new Promise((resolve, reject) => {
    functionReturningPromise().then(resolve).catch(reject);
  });
}

edit: I should clarify - according to my understanding of async/await and promises, those should all: resolve or reject according to whatever the Promise returned by functionReturningPromise does, and should make both vx and functionReturningPromise appear in the ideal stack trace. I have no doubt that they all have subtle implementation differences though.

The noise bothers me a lot less than missing frames :)

@AndreasMadsen
Copy link
Owner

I have no doubt that they all have subtle implementation differences though.

They have subtle differences in the standard too. It is about how many rounds the microtask queue take. Promise.resolve(1).then((val) => Promise.resolve(val)).then(...) results in the same as Promise.resolve(1).then(...) but they behave slightly differently.

The noise bothers me a lot less than missing frames :)

I know, but that was an issue I understood :)

@AndreasMadsen
Copy link
Owner

AndreasMadsen commented Jul 1, 2017

Okay, I have reduced it to promises. It is not exactly the same but the issue is the same:

throwing first thing:

'use strict';

function binomial() {
  return new Promise(function binomialPromise() {
    throw new Error('throwing first thing');
  });
}

function abacus() {
  return Promise.resolve().then(function abacusThen() {
    return binomial();
  });
}

abacus().catch(function (e) {
  process._rawDebug(e);
});
Error: throwing first thing
    at binomialPromise (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:5:11)
    at binomial (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:4:10)
 ** at abacusThen (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:11:12)
    at Object.<anonymous> (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:15:15)
    at abacus (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:10:28)
    at abacus (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:10:18)
    at Object.<anonymous> (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:15:1)

after timeout:

'use strict';

function binomial() {
  return Promise.resolve(/* timeout */).then(function binomialThen() {
    throw new Error('after timeout');
  });
}

function abacus() {
  return Promise.resolve().then(function abacusThen() {
    return binomial();
  });
}

abacus().catch(function (e) {
  process._rawDebug(e);
});
Error: after timeout
    at binomialThen (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:5:11)
    at Object.<anonymous> (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:15:15)
    at abacus (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:10:28)
    at abacus (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:10:18)
    at Object.<anonymous> (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:15:1)

@AndreasMadsen
Copy link
Owner

I have debugged it some more. The stack trace is actually correct, the problem is that v8 calls Error.prepareStackTrace when .stack is called and not when new Error() is called.

I will think about possible solutions to this, but I'm not sure it can be fixed.

throwing first thing

async function binomial() {
  const a = new Error('throwing first thing'); a.stack; throw a;
}

async function abacus() {
  await binomial();
}

async function main() {
  try {
    await abacus();
  } catch (e) {
    process._rawDebug(e.stack);
  }
}

main();
Error: throwing first thing
    at binomial (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:3:13)
    at abacus (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:7:9)
    at main (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:12:11)
    at Object.<anonymous> (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-first.js:18:1)

after timeout

async function binomial() {
  await Promise.resolve(/* timeout */);
  const a = new Error('after timeout'); a.stack; throw a;
}

async function abacus() {
  await binomial();
}

async function main() {
  try {
    await abacus();
  } catch (e) {
    process._rawDebug(e.stack);
  }
}

main();
Error: throwing first thing
    at binomial (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:4:13)
    at binomial (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:3:3)
    at binomial (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:3:3)
    at abacus (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:8:9)
    at main (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:13:11)
    at Object.<anonymous> (/Users/Andreas/Sites/node_modules/trace/test/scripts/await-throwing-second.js:19:1)

@fasterthanlime
Copy link
Author

Ah, so the only way out would be to have a new hook in node when it creates the Exception (rather than when .stack is accessed for the first time)?

@AndreasMadsen
Copy link
Owner

AndreasMadsen commented Jul 1, 2017

Ah, so the only way out would be to have a new hook in node when it creates the Exception (rather than when .stack is accessed for the first time)?

Yep. I tried overwriting global.Error and Error.captureStackTrace non of those allowed me to get notified, so an extra hook is needed. Allowing Error.captureStackTrace to be overwritten or extended, seems like the most straight-forward approach.


The primary reason for lazy creation of .stack is the string generation takes time. I think a good solution is to continue to delay the .stack formatting, but allow the callSite array to be modified upon new Error creation.

@fasterthanlime
Copy link
Author

I've tried following the discussion in nodejs/node but it flew way over my head :)

Is there any workaround that would work with node v8.2.1? Or is it too early still?

No pressure at all btw, just checking in as I'm still very interested in this.

@AndreasMadsen
Copy link
Owner

AndreasMadsen commented Sep 2, 2017

@fasterthanlime I'm not sure what discussion that is. There is a somewhat interesting discussion here: nodejs/node#11865

Nothing sufficiently new has happened in v8.2.1. I suppose it might be possible to setup node errors and users error to not lazy-build the stack, but even so, native JavaScript are still going to lazy-build the stack.

I think the only way to really solve this, is to involve the v8 team. I asked in nodejs/node#11865 if we can get a new Error notification feature.

@jbunton-atlassian
Copy link

I think I have a solution for this in my follow-promise-resolve branch. I use the promiseResolve async hook callback to link to extra stack frames. I also waiting until the stack is being printed to join frames rather than doing so in asyncInit, this captures more info.

It passes the existing tests as well as my new ones, however it needs a little more cleanup before I raise a PR.

@AndreasMadsen
Copy link
Owner

@jbunton-atlassian I'm excited that you are investigating this, but I'm very skeptical.

I'm very skeptical because no matter what you won't get the frames from the point of view where new Error() was created, unless you capture new Error(). The issue is actually bigger than just promises.

function asyncFunction(callback) {
  process.nextTick(callback, new Error('error'))
}

asyncFunction(function (err) {
  process.nextTick(() => throw err)
})

will suffer from the same issue, because the long-stack-trace is collected at throw err not new Error().

I use the promiseResolve async hook callback to link to extra stack frames.

Using the promiseResolve "solves" a different issue, where the stack trace for what is between the start of the promise and the resolve call isn't included.

I also waiting until the stack is being printed to join frames rather than doing so in asyncInit, this captures more info.

As I see it, you just represent the long-stack-trace as a linked list. So I don't really see what extra information you get. Can you clarify?

It passes the existing tests as well as my new ones, however it needs a little more cleanup before I raise a PR.

Okay, I will be happy to review when you are done.

@jbunton-atlassian
Copy link

Hi there. I think I've solved this in #40. I'd love any feedback or testing anybody could give this code :)

You can try it out by installing it from my repo:

npm install 'git://github.com/jbunton-atlassian/trace#a4e78d89e09ab4830f302bf85a30a528a5746e0b'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants