> The way promises are chained means that some patterns like async loops would > theoretically unroll to very long stack traces
Devtools in fact does that (has a button at the bottom of the stack to keep loading more frames). I think it would be better for it to be smart and not have duplicate frames in the stack, so a loop would result in only one unique set of entries in the stack trace and not repeat. #!/JoePea On Sun, Jul 12, 2020 at 11:53 AM Jacob Bloom <[email protected]> wrote: > > Reading through the issue JoePea linked to, it looks like the difficulties > with standardized async stack traces are twofold: > > 1. Even with the error stacks proposal, the implementer has total say over > what qualifies as a stack frame > 2. The way promises are chained means that some patterns like async loops > would theoretically unroll to very long stack traces, and right now engines > aren't required to keep track of those frames; requiring them to do so would > place a burden on implementers that could quickly lead to slowdowns and > memory issues > > What if there was a standard way to mark a Promise as an important stack > frame, which the implementer is free to ignore? Maybe something like > `Promise.prototype.trace()` > > On Fri, Jul 10, 2020 at 10:22 PM #!/JoePea <[email protected]> wrote: >> >> Hello Kai! That example is so meta with its own output showing the >> numbers relative to the code including its own output! :) >> >> That's what I originally wanted to do, but that doesn't give us an >> async stack trace, it only gives a sync stack trace (I presume within >> the current event loop task). >> >> For example: >> >> ```js >> const originalFetch = globalThis.fetch >> >> globalThis.fetch = function(...args) { >> const stack = new Error().stack >> console.log(stack) >> return originalFetch.apply(globalThis, args) >> } >> >> const sleep = t => new Promise(r => setTimeout(r, t)) >> >> async function one() { >> console.log('1') >> await sleep(10) >> two() >> } >> >> async function two() { >> console.log('2') >> await sleep(10) >> three() >> } >> >> async function three() { >> console.log('3') >> await sleep(10) >> return await fetch('https://unpkg.com/[email protected]') >> } >> >> async function main() { >> await one() >> } >> >> main() >> ``` >> >> Output: >> >> ``` >> 1 >> 2 >> 3 >> Error >> at globalThis.fetch (pen.js:5) >> at three (pen.js:27) >> ``` >> >> Live example: >> >> https://codepen.io/trusktr/pen/b8fd92752b4671268f516ad3804869e4?editors=1010 >> >> I opened a request for this over here: >> https://github.com/tc39/proposal-error-stacks/issues/34 >> >> #!/JoePea >> >> On Fri, Jul 10, 2020 at 1:21 PM kai zhu <[email protected]> wrote: >> > >> > > (I want to detect traces in third-party code installed locally). >> > >> > 1. here's 15-line javascript-hack to trace async-fetch-calls from >> > 3rd-party-cdn-library >> > >> > ```html >> > <!doctype html> >> > <html lang="en"> >> > <body> >> > <h1>test.html</h1> >> > <script> >> > (function () { >> > /* >> > * 15-line-javascript-hack to trace async-fetch-calls >> > * enable hack by adding search-query "?modeDebugFetch=1" to web-url >> > */ >> > "use strict"; >> > if ((/\bmodeDebugFetch=1\b/).test(location.search)) { >> > let fetch0; >> > fetch0 = globalThis.fetch; >> > globalThis.fetch = function (...argList) { >> > let errStack = new Error().stack; >> > console.error("\n\nfetch-call-arguments:"); >> > console.error(JSON.stringify(argList, undefined, 4)); >> > console.error("\n\nfetch-call-trace:"); >> > console.error(errStack); >> > return fetch0(...argList); >> > }; >> > } >> > }()); >> > </script> >> > <!-- 3rd-party-cdn-library --> >> > <script src="https://unpkg.com/http-client/umd/http-client.js"></script> >> > <script> >> > (async function foo() { >> > "use strict"; >> > let thirdParty = window.HTTPClient; >> > let myFetch = thirdParty.createFetch( >> > thirdParty.base("https://api.stripe.com/v1"), >> > thirdParty.accept("application/json") >> > ); >> > let response = await myFetch("/customers/5"); >> > console.log(response.jsonData); >> > /* >> > dev-console-output - http://localhost:8081/test.html?modeDebugFetch=1 >> > fetch-call-arguments: >> > [ >> > "https://api.stripe.com/v1/customers/5", >> > { >> > "headers": { >> > "Accept": "application/json" >> > }, >> > "responseHandlers": [ >> > null >> > ] >> > } >> > ] >> > fetch-call-trace: >> > Error >> > at globalThis.fetch (test.html?modeDebugFetch=1:16) >> > at http-client.js:194 >> > at http-client.js:127 >> > at http-client.js:217 >> > at http-client.js:126 >> > at http-client.js:154 >> > at http-client.js:95 >> > at foo (test.html?modeDebugFetch=1:35) >> > at test.html?modeDebugFetch=1:64 >> > */ >> > }()); >> > </script> >> > </body> >> > ``` >> > >> > >> > 2. here's real-world-hack added to npm-cli.js to debug its http-requests >> > >> > ```diff >> > C:\Program Files\nodejs\node_modules\npm>git diff >> > diff --git a/bin/npm-cli.js b/bin/npm-cli.js >> > index 561dec0..98cafb8 100644 >> > --- a/bin/npm-cli.js >> > +++ b/bin/npm-cli.js >> > @@ -2,17 +2,6 @@ >> > ;(function () { // wrapper in case we're in module_context mode >> > +// hack - debug http-request >> > +let httpRequest; >> > +httpRequest = require("https").request.bind(require("https")); >> > +require("https").request = function (...argList) { >> > + if (process.env.NPM_DEBUG) { >> > + console.error( >> > + "npm - httpRequest - " + JSON.stringify(argList.slice(0, 2), >> > undefined, 4) >> > + ); >> > + } >> > + return httpRequest(...argList); >> > +}; >> > // windows: running "npm blah" in this folder will invoke WSH, not node. >> > >> > C:\Program Files\nodejs\node_modules\npm> >> > ``` >> > >> > ```mingw-bash >> > $ NPM_DEBUG=1 npm publish foo >> > # console-ouput: >> > # npm - httpRequest - [ >> > # { >> > # "protocol": "https:", >> > # "href": "https://registry.npmjs.org/foo", >> > # "method": "GET", >> > # "headers": { >> > # "connection": [ >> > # "keep-alive" >> > # ], >> > # "user-agent": [ >> > # "npm/6.13.4 node/v12.16.1 win32 x64" >> > # ], >> > # ... >> > ``` >> > >> > >> > >> > >> > >> > On Fri, Jul 10, 2020 at 3:34 AM #!/JoePea <[email protected]> wrote: >> >> >> >> Thanks for the idea! That's similar to what I thought would be necessary. >> >> I was hoping to monkey patch `fetch()` to have it get the trace if any >> >> `fetch` call, but they would not be async stack traces. For async traces >> >> it would require instrumentation by injecting code similar to yours (I >> >> want to detect traces in third-party code installed locally). >> >> >> >> #!/JoePea >> >> >> >> On Wed, Jul 8, 2020, 2:13 AM kai zhu <[email protected]> wrote: >> >>> >> >>> here's a simple throwaway-function you can wrap around promises like >> >>> fetch >> >>> to get the caller's async-stack-trace `promiseWithErrorStack`: >> >>> >> >>> ```html >> >>> <!doctype html> >> >>> <html lang="en"> >> >>> <body> >> >>> <h1>test.html</h1> >> >>> <script> >> >>> (async function foo() { >> >>> function promiseWithErrorStack(promise) { >> >>> /* >> >>> * this function will append current-stack to any err caught from >> >>> <promise> >> >>> */ >> >>> let errStack; >> >>> errStack = new Error().stack; >> >>> return new Promise(function (resolve, reject) { >> >>> promise.then(resolve).catch(function (err) { >> >>> // append current errStack to err.stack >> >>> if (err && typeof err.stack === "string") { >> >>> err.stack += "\n" + errStack; >> >>> } >> >>> reject(err); >> >>> }); >> >>> }); >> >>> } >> >>> await promiseWithErrorStack(fetch("https://example.com")); // at foo >> >>> (test.html:23) >> >>> >> >>> /* >> >>> console-output: >> >>> >> >>> Uncaught (in promise) TypeError: Failed to fetch >> >>> Error >> >>> at promiseWithErrorStack (test.html:12) >> >>> at foo (test.html:23) // async-stack-trace >> >>> at test.html:32 >> >>> */ >> >>> }()); >> >>> </script> >> >>> </body> >> >>> ``` >> >>> >> >>> On Tue, Jul 7, 2020 at 11:54 PM #!/JoePea <[email protected]> wrote: >> >>>> >> >>>> Is there some way (perhaps by patching methods on objects?) so we can >> >>>> track async call stacks? >> >>>> >> >>>> When we pause code in devtools, we are able to see the async stack >> >>>> trace of the code. >> >>>> >> >>>> What I'd like to do is to effectively detect the same thing as >> >>>> devtools does at some point in any code. As a specific example, I'd >> >>>> like to detect the async stack trace of any call to `fetch`. >> >>>> >> >>>> Is such a thing possible with runtime code? >> >>>> >> >>>> Or would it require instrumentation of the source code? >> >>>> >> >>>> #!/JoePea >> >>>> _______________________________________________ >> >>>> es-discuss mailing list >> >>>> [email protected] >> >>>> https://mail.mozilla.org/listinfo/es-discuss >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss _______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

