带有 fs/promises 和 async..await 的堆栈跟踪

发布于 2025-01-18 04:58:19 字数 1798 浏览 1 评论 0原文

我有一个类似于这个问题 并在此问题中进行了描述。当与 async..await 一起使用时,来自 fs/promises 的错误中没有堆栈跟踪,并且无法确定错误发生的位置。

给定应用程序:

foo.js

const { bar } = require('./bar');

async function foo() {
  await bar();
}


(async () => {
  await foo();
})().catch(console.error);

bar.js

const fs = require('fs/promises');

exports.bar = async function bar() {
  await fs.readFile('some');
}

当它像 node foo.js 一样运行时,这会导致没有堆栈跟踪的错误:

[Error: ENOENT: no such file or directory, open '...\some'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: '...\\some'
}

其中 error.stack 包含'ENOENT:没有这样的文件或目录,打开'...\some'。

当它像 node --stack_trace_limit=100 -r trace foo.jstrace 包一样运行时,就像链接源中建议的那样,这会导致以下堆栈跟踪:

stack Trace

请注意,内部条目呈灰色,可以过滤掉。

这个带有 traceclarify 包的 node --stack_trace_limit=100 -r trace -r recognize foo.js 会产生以下输出:

Error: ENOENT: no such file or directory, open '...\some'
    at ...\foo.js:8:2
    at Object.<anonymous> (...\foo.js:10:3) {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: '...\\some',
  [Symbol(originalCallSite)]: [],
  [Symbol(mutatedCallSite)]: [ CallSite {}, CallSite {} ]
}

问题是所有输出中均未提及 bar.js

我的目的是提供干净的错误输出,没有内部条目以及错误发生的确切位置,即 bar.js 中的行号。

这个问题有哪些可能的解决方案?

I have a problem that is similar to this one and described in this issue. There are no stack traces in errors that come from fs/promises when used with async..await, and no way to determine where the error happened.

Given the app:

foo.js

const { bar } = require('./bar');

async function foo() {
  await bar();
}


(async () => {
  await foo();
})().catch(console.error);

bar.js

const fs = require('fs/promises');

exports.bar = async function bar() {
  await fs.readFile('some');
}

When it runs like node foo.js, this results in an error with no stack trace:

[Error: ENOENT: no such file or directory, open '...\some'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: '...\\some'
}

Where error.stack contains 'ENOENT: no such file or directory, open '...\some'.

When it runs like node --stack_trace_limit=100 -r trace foo.js with trace package, like it's suggested in linked sources, this results in this stack trace:

stack trace

Notice that internal entries are grayed and can be filtered out.

This node --stack_trace_limit=100 -r trace -r clarify foo.js with trace and clarify packages results in this output:

Error: ENOENT: no such file or directory, open '...\some'
    at ...\foo.js:8:2
    at Object.<anonymous> (...\foo.js:10:3) {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: '...\\some',
  [Symbol(originalCallSite)]: [],
  [Symbol(mutatedCallSite)]: [ CallSite {}, CallSite {} ]
}

The problem is that bar.js isn't mentioned in all of the outputs.

My intention is to provide clean error output with no internal entries and the exact location where the error occurs, i.e. line number in bar.js.

What are possible solutions to this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

愛放△進行李 2025-01-25 04:58:19

由于问题的根本原因是 fs/promises Error 在设计上没有堆栈,为什么当您需要堆栈详细信息时不抛出自己的堆栈呢?

除此之外,我建议避免使用 Promise 的 catch 方法,而仅使用 async/await 构造。

foo.js

const { bar } = require('./bar');

async function foo() {
  await bar();
}

(async function main() {
  try {
    await foo();
  } catch(e) {
    console.error(e);
  }
})();

bar.js

const fs = require('fs/promises');

exports.bar = async function bar() {
  try{
    await fs.readFile('some');
  } catch(e) {
    throw new Error(e.message);
  }
};

这给出了以下结果:

Error: ENOENT: no such file or directory, open 'some'
    at bar (/home/me/test/bar.js:7:11)
    at async foo (/home/me/test/foo.js:4:3)
    at async main (/home/me/test/foo.js:9:5)

可能您不需要使用 trace 和/或 clarify ,但是当然您仍然可以根据需要自由地使用它们来更改堆栈跟踪。

Since the root cause of your problem is that fs/promises Errors have no stack by design, why simply not throwing your own when you need stack details?

More than this I can suggest to avoid using the catch method of promises and to use only the async/await construct.

foo.js

const { bar } = require('./bar');

async function foo() {
  await bar();
}

(async function main() {
  try {
    await foo();
  } catch(e) {
    console.error(e);
  }
})();

bar.js

const fs = require('fs/promises');

exports.bar = async function bar() {
  try{
    await fs.readFile('some');
  } catch(e) {
    throw new Error(e.message);
  }
};

This gives following result:

Error: ENOENT: no such file or directory, open 'some'
    at bar (/home/me/test/bar.js:7:11)
    at async foo (/home/me/test/foo.js:4:3)
    at async main (/home/me/test/foo.js:9:5)

Probably you neither need to use trace and/or clarify, but of course you are still free to use them to alter the stack trace at your needs.

十年不长 2025-01-25 04:58:19

如此接近:)

编辑:
基于 fs/promise 问题
这是一个已知问题,可以根据需要解决,如下所示。

此节点 --stack_trace_limit=100 -r trace -r 澄清 foo.js
使用跟踪和澄清包会产生以下输出:

错误:ENOENT:没有这样的文件或目录,打开“...\some”
在 ...\foo.js:8:2
在对象。 (...\foo.js:10:3) {
错误号:-4058,
代码:'ENOENT',
系统调用:'打开',
路径:'...\一些',
[符号(originalCallSite)]:[],
[符号(mutatedCallSite)]:[ CallSite {},CallSite {} ]
}

问题是在所有输出中都没有提到bar.js

除了使用跟踪/澄清之外,
直接在 fs.readFile 调用(bar.js)上尝试/捕获

const fs = require('fs/promises');

exports.bar = async () => {
    try {
        await fs.readFile('some');
    } catch (e) {
        console.error(e);
    }
}

$ node --stack_trace_limit=100 -r trace -r clarify foo.js
Error: ENOENT: no such file or directory, open 'some'
    at emitInitNative (node:internal/async_hooks:205:43)
    at emitInitNative (node:internal/async_hooks:205:43)
    at emitInitScript (node:internal/async_hooks:495:3)
    at promiseInitHook (node:internal/async_hooks:325:3)
    at promiseInitHookWithDestroyTracking (node:internal/async_hooks:329:3)
    at Object.readFile (node:internal/fs/promises:786:24)

    at exports.bar (/home/lz/code/stackover/bar.js:6:18)

    at foo (/home/lz/code/stackover/foo.js:4:11)
    at /home/lz/code/stackover/foo.js:9:15
    at Object.<anonymous> (/home/lz/code/stackover/foo.js:13:3)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47 {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

您也可以尝试同步读取文件。

So close :)

Edit:
based on fs/promise issue,
it's a known issue, and could be worked-around on demand, as suggested below.

This node --stack_trace_limit=100 -r trace -r clarify foo.js
with trace and clarify packages results in this output:

Error: ENOENT: no such file or directory, open '...\some'
at ...\foo.js:8:2
at Object. (...\foo.js:10:3) {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: '...\some',
[Symbol(originalCallSite)]: [],
[Symbol(mutatedCallSite)]: [ CallSite {}, CallSite {} ]
}

The problem is that bar.js isn't mentioned in all of the outputs.

In addition for using trace/clarify,
do try/catch directly on fs.readFile call (bar.js)

const fs = require('fs/promises');

exports.bar = async () => {
    try {
        await fs.readFile('some');
    } catch (e) {
        console.error(e);
    }
}

$ node --stack_trace_limit=100 -r trace -r clarify foo.js
Error: ENOENT: no such file or directory, open 'some'
    at emitInitNative (node:internal/async_hooks:205:43)
    at emitInitNative (node:internal/async_hooks:205:43)
    at emitInitScript (node:internal/async_hooks:495:3)
    at promiseInitHook (node:internal/async_hooks:325:3)
    at promiseInitHookWithDestroyTracking (node:internal/async_hooks:329:3)
    at Object.readFile (node:internal/fs/promises:786:24)

    at exports.bar (/home/lz/code/stackover/bar.js:6:18)

    at foo (/home/lz/code/stackover/foo.js:4:11)
    at /home/lz/code/stackover/foo.js:9:15
    at Object.<anonymous> (/home/lz/code/stackover/foo.js:13:3)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47 {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

You can also try sync read file.

无言温柔 2025-01-25 04:58:19

一种可能的解决方案是使用 Node.js >= v21.2.0Node.js 版本 v21.2.0 包含 提交 来自 PR 49849 将堆栈跟踪添加到 node:fs/promises

ES 模块和顶层等待着您。

package.json

"type": "module"

bar.js

import { readFile } from 'node:fs/promises'

export async function bar() {
  await readFile('some')
}

foo.js

import { bar } from './bar.js'

await bar()

现在运行 node foo.js 生成堆栈跟踪:

node:internal/fs/promises:638
  return new FileHandle(await PromisePrototypeThen(
                        ^

Error: ENOENT: no such file or directory, open 'some'
    at async open (node:internal/fs/promises:638:25)
    at async readFile (node:internal/fs/promises:1251:14)
    at async bar (file:///Users/user/async-stack-trace/bar.js:4:5)
    at async file:///Users/user/async-stack-trace/foo.js:4:1 {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

Node.js v22.1.0

ES具有异步功能的模块(无顶级等待)。

foo.js

import { bar } from './bar.js'

async function main() {
  await bar()
}

main()

运行 node foo.js 后会产生类似的堆栈跟踪:

node:internal/fs/promises:638
  return new FileHandle(await PromisePrototypeThen(
                        ^

Error: ENOENT: no such file or directory, open 'some'
    at async open (node:internal/fs/promises:638:25)
    at async readFile (node:internal/fs/promises:1251:14)
    at async bar (file:///Users/user/async-stack-trace/bar.js:4:5)
    at async main (file:///Users/user/async-stack-trace/foo.js:4:3) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

Node.js v22.1.0

CommonJS

package.json

"type": "commonjs"

bar.js

const { readFile } = require('node:fs/promises')

exports.bar = async function bar() {
  await readFile('some')
}

const { bar } = require('./bar.js')

async function main() {
  await bar()
}

main()

node foo.js

node:internal/fs/promises:638
  return new FileHandle(await PromisePrototypeThen(
                        ^

Error: ENOENT: no such file or directory, open 'some'
    at async open (node:internal/fs/promises:638:25)
    at async readFile (node:internal/fs/promises:1251:14)
    at async bar (/Users/user/async-stack-trace/src/bar.js:4:3)
    at async main (/Users/user/async-stack-trace/src/foo.js:4:3) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

Node.js v22.1.0

One possible solution is to use Node.js >= v21.2.0. Node.js release v21.2.0 included a commit from PR 49849 that adds stack traces to node:fs/promises.

ES modules and top level await.

package.json

"type": "module"

bar.js

import { readFile } from 'node:fs/promises'

export async function bar() {
  await readFile('some')
}

foo.js

import { bar } from './bar.js'

await bar()

Now run node foo.js to generate the stack trace:

node:internal/fs/promises:638
  return new FileHandle(await PromisePrototypeThen(
                        ^

Error: ENOENT: no such file or directory, open 'some'
    at async open (node:internal/fs/promises:638:25)
    at async readFile (node:internal/fs/promises:1251:14)
    at async bar (file:///Users/user/async-stack-trace/bar.js:4:5)
    at async file:///Users/user/async-stack-trace/foo.js:4:1 {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

Node.js v22.1.0

ES modules with async function (no top level await).

foo.js

import { bar } from './bar.js'

async function main() {
  await bar()
}

main()

Which after running node foo.js results in a similar stack trace:

node:internal/fs/promises:638
  return new FileHandle(await PromisePrototypeThen(
                        ^

Error: ENOENT: no such file or directory, open 'some'
    at async open (node:internal/fs/promises:638:25)
    at async readFile (node:internal/fs/promises:1251:14)
    at async bar (file:///Users/user/async-stack-trace/bar.js:4:5)
    at async main (file:///Users/user/async-stack-trace/foo.js:4:3) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

Node.js v22.1.0

CommonJS

package.json

"type": "commonjs"

bar.js

const { readFile } = require('node:fs/promises')

exports.bar = async function bar() {
  await readFile('some')
}

foo.js

const { bar } = require('./bar.js')

async function main() {
  await bar()
}

main()

After running node foo.js:

node:internal/fs/promises:638
  return new FileHandle(await PromisePrototypeThen(
                        ^

Error: ENOENT: no such file or directory, open 'some'
    at async open (node:internal/fs/promises:638:25)
    at async readFile (node:internal/fs/promises:1251:14)
    at async bar (/Users/user/async-stack-trace/src/bar.js:4:3)
    at async main (/Users/user/async-stack-trace/src/foo.js:4:3) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'some'
}

Node.js v22.1.0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文