如何更改本地运行的 Node.js 项目中的 Promise 构造函数?

pmr*_*ule 5 c++ v8 node.js nvm

这可能听起来很奇怪,但我想更改本地 Node.js 版本并修改实现Promise以添加新的source实例属性。

global.Promise = class SourcePromise extends Promise {
  constructor(params) {
    super(params)
    this.source = new Error('This is where this promise was created').stack
  }
}
Run Code Online (Sandbox Code Playgroud)

这将帮助我调试 Nuxt 应用程序上发生的错误,但仅限于服务器上。我可以通过监听unhandledRejection事件来捕获错误,但返回的错误不是一个Error对象,它只是undefined所以我不知道它来自哪里。的回调unhandledRejection也返回承诺,因此我尝试在nuxt start脚本的最开头添加上面的代码片段,以便能够记录源代码,如下所示:

process.on('unhandledRejection', (error, promise) => {
  console.log('Unhandled Rejection:', error?.stack)
  console.log('Promise source:', promise.source)
})
Run Code Online (Sandbox Code Playgroud)

promise.source也是未定义的。如果我从任何脚本登录console.log(Promise.resolve().source),它就会起作用并且我会获得源代码,因此我想到的唯一解释是承诺是在Promise未定义我的扩展的子进程中创建的。

总而言之,由于它发生在一个单独的进程中,并且我无法确定是哪个进程,所以我认为SourcePromise在所有 Node 进程中全局实现的唯一方法是Promise直接在本地版本的 Node 中更改定义。有可能吗?

我在 macOS Monterey 12.3.1 上使用 nvm v0.38.0

编辑

我最终从 Github 克隆了Node.js,以便能够在本地构建它并使用它来启动我的 Nuxt 服务器。问题是:它是用 C++ 编写的,我不明白。我想我找到了Promise 构造函数的定义位置,它调用的NewJsPromise似乎是在此处定义的,但我需要 C++ 开发人员的帮助,因为我仍然不知道如何或在哪里添加堆栈...

jmr*_*mrk 2

(这里是 V8 开发人员。)前面的坏消息:我不知道到底如何做你所要求的事情,而且我没有时间为你弄清楚。

但由于到目前为止您还没有得到其他答案,我将尝试说一些可能有助于您取得进展的事情:

  • 我不认为这是一个“单独进程”的问题。JS 对象(包括 Promise)不能在进程之间移动。如果您在一个进程中看到它,那么它是在同一进程中创建的。
  • V8 中有不止一段代码可以创建 Promise,因此为了确保您能够捕获有问题的 Promise,您必须更新所有代码:
    1. NewJSPromise在 中src/builtins/promise-misc.tq,您发现了 Torque(不是 C++!)实现,用于 JavaScriptPromise构造函数和其他几个内置函数。请注意,如果您仅将修改放入PromiseConstructor,则会跳过该帮助器的其他用途,因此请务必更新NewJSPromise
    2. Factory::NewJSPromisein中有 C++ 版本src/heap/factory.cc(可能除其他外,还用于 V8 的 API,即 Node 本身或自定义 Node 附加组件创建 Promise 的任何情况)。
    3. PromiseBuiltinReducerAssembler::ReducePromiseConstructorin中的优化编译器提供内联支持src/compiler/js-call-reducer.cc(这可能可以通过禁用编译器对内联 Promise 创建的支持来解决)。
  • 您要做的事情的总体轮廓是:
    1. 更新Promise对象定义以包含另一个字段。
    2. 看一下Error对象是如何创建的,就知道如何获取堆栈了。Error出于性能原因,对象对堆栈跟踪采用一些奇特的“惰性创建”方案;遵循该示例可能会更容易(以最大限度地减少分歧),或者简化它可能会更容易(因为您不关心性能)。请注意,AFAICTError对象始终是用 C++ 创建的;你必须弄清楚如何让堆栈达到扭矩创建的承诺(我对此没有什么好的建议)。
    3. 更新创建 Promise 的所有位置(见上文)以相应地初始化新字段。
  • 我强烈怀疑有更少耗时的方法来调试您的原始问题。(我不知道,也许只是审核所有处理承诺的地方,并检查它们是否都有拒绝处理程序?这可能需要几个小时,但很可能比上面概述的 V8 修改项目花费的时间更少。)

祝您调查顺利!