For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-error-limit-option.md.
  • 简体中文
  • Error option limit S1

    中文标题:错误选项 limit

    提案概览
    提案速览

    该提案为所有内置 Error 构造函数引入了一个按错误实例的选项 limit,用于控制每个错误实例捕获的最大堆栈帧数。它解决了全局 Error.stackTraceLimit 的问题,如粒度粗、全局副作用和样板解决方案。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    ECMAScript 提案:错误选项 limit

    状态

    提案发起人:Ruben Bridgewater

    作者:Ruben Bridgewater ruben@bridgewater.de

    阶段:1

    概述

    本提案为每个错误引入了一个新的 Error 选项属性 limit,该属性指定了为该特定错误实例捕获的最大实现定义的堆栈帧数量。

    • limit 是一个数值选项,使用 ToIntegerOrInfinity 解释。
    • 如果提供,局部 limit 会覆盖任何全局堆栈跟踪限制(例如,V8 的 Error.stackTraceLimit)仅针对该错误。
    • 负值抛出 RangeError;limit 必须是非负整数、undefinedInfinity
    • 从概念上讲,这类似于在创建错误之前临时设置 V8 特定的 Error.stackTraceLimit,并在之后立即恢复,但没有任何全局副作用。

    这提供了一种标准化的、跨引擎的方式来控制每个错误实例的堆栈深度,并避免操作影响无关错误的全局开关。

    提议的 API

    new Error(message, { limit: 3 })
    new TypeError(message, { limit: 0 })
    new RangeError(message, { limit: 50 })
    new AggregateError(iterable, message, { limit: Infinity })
    // ... 适用于所有接受选项对象的内置 Error 构造函数

    验证

    • 如果提供了 options 并且其 limit 属性值不是 undefined,引擎计算 n = ToIntegerOrInfinity(limit)
      • 如果 n < 0,抛出 RangeError
      • 否则,将 n 记录在错误实例上。
    • 如果 limitundefined 或缺失,默认行为不变(如果存在全局限制,则应用全局限制)。

    理由:局部限制更直观

    • V8 中定义的全局 Error.stackTraceLimit 粒度较粗,会影响所有错误,包括那些不需要更深堆栈的错误。
    • 每个错误的 limit 在关键处准确表达了意图,避免了意外的全局副作用。
    • 局部限制总是覆盖该特定错误实例的全局限制,这符合开发者在定制诊断信息时的期望。
    • 消除了仅为了构造一个错误而临时修改全局 Error.stackTraceLimit 的样板模式。

    为什么 V8 中定义的全局 Error.stackTraceLimit 容易出错

    • 更改是进程范围且基于时间的,因此无关的错误可能继承错误的限制。
    • “设置”和“重置”之间的代码可能同步抛出异常,跳过重置。
    • 异步边界使得在 await 期间很容易影响其他正在进行的任务。
    • 人们有时只是忘记重置全局开关。

    示例:

    1. 错误创建期间同步抛出异常会跳过重置
    // 如果消息强制转换抛出异常,全局修改永远不会重置
    const prev = Error.stackTraceLimit;
    Error.stackTraceLimit = 2;
    
    // toString 可能在 Error(message) 强制转换期间抛出异常
    const msg = { toString() { throw new TypeError('format failed'); } };
    new Error(msg); // 在任何重置运行之前抛出;全局现在卡在 2

    使用局部限制,没有全局修改:

    throw new Error('boom', { limit: 2 });
    1. 异步危险:无关的错误使用您的临时限制
    async function makeErrorLater() {
      const prev = Error.stackTraceLimit;
      Error.stackTraceLimit = Infinity; // 意图:为这一个错误获取深度堆栈
    
      // 与此同时,在此 await 期间执行的其他任务也将看到 Infinity。
      await doWorkElsewhere();
    
      const err = new Error('x'); // 获取深度堆栈...
      Error.stackTraceLimit = prev; // ...但 await 期间的其他错误也获取了。
    }

    使用局部限制,只有预期的错误受到影响:

    async function makeErrorLater() {
      await doWorkElsewhere();
      throw new Error('x', { limit: Infinity });
    }
    1. 简单遗漏:忘记重置
    Error.stackTraceLimit = 1;
    // ... 时间流逝,代码演进 ...
    // 重置被遗忘;所有后续错误现在都有过短的堆栈

    每个错误的 limit 避免了整个类别的错误。

    使用场景

    • 性能敏感的热路径,只需要前几帧(例如,limit: 2)以最小化开销。
    • 针对特定错误类型或代码路径的聚焦深度调试(例如,limit: 100Infinity),而不改变其他错误的行为。
    • 库和框架工具希望对其自身的诊断错误具有可预测的堆栈深度,而不全局影响用户代码。

    实际中(先行实践)

    开发者经常通过在创建错误之前临时更改全局 Error.stackTraceLimit 并在之后重置来模拟每个错误的控制。示例和参考:

    • MDN: Error.stackTraceLimit (记录了临时调整模式) — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stackTraceLimit
    • Node.js 文档: Errors — https://nodejs.org/api/errors.html
    • GitHub 代码搜索: “Error.stackTraceLimit = Infinity” — https://github.com/search?q=%22Error.stackTraceLimit+%3D+Infinity%22&type=code
    • longjohn (异步堆栈跟踪) 设置非常高/Infinity 限制 — https://github.com/mattinsler/longjohn
    • Mocha 完整跟踪选项 (“完整堆栈”的生态系统先例) — https://mochajs.org/#--full-trace

    这些表明开发者已经依赖每个错误或上下文本地的堆栈深度控制;标准化每个错误的 limit 消除了全局修改的需求。

    语义

    • L 为错误实例记录的 limit,如果提供;否则为 undefined
    • 当宿主为错误捕获堆栈时:
      • 如果 Lundefined,应用宿主的默认/全局堆栈跟踪限制。
      • 否则,仅对该错误应用 L 作为限制。
    • 格式化以及任何其他宿主定义的堆栈处理保持不变。

    stack frame 是实现定义的。

    规范文本(大纲)

    1. 在每个接受选项参数的 Error(及子类)构造函数中:
      • options 为第二个(或对于 AggregateError 是第三个)参数。
      • 如果 options 不是 undefined
        • limit 为 ? Get(options, "limit").
        • 如果 limit 不是 undefined
          • n 为 ? ToIntegerOrInfinity(limit).
          • 如果 n < 0,抛出 RangeError
          • 在错误实例的内部槽中记录 n,以供堆栈捕获时后续使用。
    2. 当为错误实例 E 捕获堆栈时:
      • S 为在没有此选项时将为 E 捕获的帧序列。
      • nE.[[StackTraceLimitOverride]],如果存在;否则为 undefined
      • 应用堆栈长度限制:
        • 如果 nundefined,应用宿主的全局/默认限制。
        • 否则,应用 nS
      • 照常从 S 生成堆栈字符串。

    查看完整规范草案:

    非目标与边界情况

    • 本提案不标准化堆栈字符串格式、源映射应用或异步堆栈合并。
    • 如果 limit0,除了错误标题(实现定义)外,错误不包含帧。
    • 该选项是每个错误的,不影响其他错误或将来的堆栈捕获。

    考虑的替代方案

    • 继续使用全局 Error.stackTraceLimit。因缺乏精度、意外的全局副作用以及模拟每个错误控制所需的样板而被拒绝。
    • 添加新的主机特定 API。已拒绝;标准化语言选项更具可移植性和互操作性。

    结论

    limit 提供了一种显式、局部的方式来控制每个错误的堆栈深度,符合开发者的期望,改善了人体工程学,避免了全局副作用,同时与生态系统实践保持一致。