第 3 章 代码

第 3 章 代码覆盖50个正式坐标,用假设阶梯、工件三角校验与迁移门交付最小复现、结构化错误链、async上下文轨迹、event-loop信号、addon ABI矩阵和退出日志

学习目标

  • 把Promise、Async/Await、Error Stack、Node 8、Rust Addons、Event Loop与uncaughtException放进“症状—假设—原始工件—反证—恢复”诊断链
  • 只注入“把最终uncaughtException监听器当成可继续运行的恢复机制”,定位第 3 章 代码相对稳定基线的首个分岔
  • 交付最小复现、结构化错误链、async上下文轨迹、event-loop信号、addon ABI矩阵和退出日志,严格分开Node 8.9.4原作与当前Node迁移轨道

为什么从这个症状开始

第 3 章 代码围绕“异步错误、事件循环停顿和原生边界怎样保留首个因果链?”建立贯穿任务:用一个含Promise拒绝、定时器、I/O、nextTick与原生边界的固定用例重放错误和时序。先把“错误栈断裂、请求挂起或吞吐在代码变更后下降”写成可重复症状,再对齐参考、单故障和恢复工件;只有守住“代码诊断必须保留原始错误、异步上下文、队列阶段、Node/V8身份和安全退出”并交付最小复现、结构化错误链、async上下文轨迹、event-loop信号、addon ABI矩阵和退出日志,工具输出才可能升级为根因证据。

原版、版本与转载边界

第 3 章 代码以赵坤作者仓库为原版一手基线:仓库公开30篇完整章节与配图索引,README明确开发环境为MacOS/Linux(Ubuntu 16.04 64位)和Node.js 8.9.4。本站将原版比较固定到提交403f5c6,该提交时间为2019年5月23日。

第 3 章 代码同时用版本记录核对赵坤著、电子工业出版社、2018年5月、248页、ISBN 9787121341465及八章内容概述。作者仓库与版本描述共同证明原作先后是CPU、内存、代码、工具、APM、日志、监控、应用;本站旧清单曾把第5章日志与第6章APM对调,本次已按作者原版修正。

第 3 章 代码的来源访问级别是 full-text-primary,但作者仓库没有LICENSE文件。公开可读不等于转载授权:本站不复制原文段落、示例代码、截图或图像,只用其核对原作问题、工具身份和历史语境,再以独立中文教学结构重写。

第 3 章 代码把两个时代分轨:历史轨道保留Node 8.9.4、Ubuntu 16.04、v8-profiler、memwatch-next、process._debugProcess、OpenTracing和当时APM/平台;当前轨道以Node官方文档和维护方资料核对内置CPU/heap profile、Inspector、diagnostic report、AsyncLocalStorage、Node-API、OpenTelemetry以及各工具当前维护状态。当前能力不能倒灌成原作者观点。

第 3 章 代码的heap snapshot可能阻塞事件循环并需要约两倍堆内存,core/heap/report可能含敏感数据,Inspector端点可执行任意代码。生产采集必须先做数据分级、磁盘/内存预算、访问控制、脱敏、停止条件和副本复现;页面是实验协议,不是盲目执行清单。

本页独立事实来源

原版正式坐标逐项解释

第3章 代码

坐标 1/50:第3章 代码。稳定证据键 NDBG-UNIT03-A。 第 3 章 代码把第3章 代码设为诊断入口而非工具清单:先固定用户症状、请求集、运行时身份和安全预算,再选择章内工件。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1 Promise

坐标 2/50:3·1 Promise。稳定证据键 NDBG-UNIT03-B。 第 3 章 代码把3·1 Promise回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.1 Promise/A规范

坐标 3/50:3·1·1 Promise/A规范。稳定证据键 NDBG-UNIT03-C。 第 3 章 代码把3·1·1 Promise/A规范回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.2 从零开始实现Promise

坐标 4/50:3·1·2 从零开始实现Promise。稳定证据键 NDBG-UNIT03-D。 第 3 章 代码把3·1·2 从零开始实现Promise回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.3 Promise的实现原理

坐标 5/50:3·1·3 Promise的实现原理。稳定证据键 NDBG-UNIT03-E。 第 3 章 代码把3·1·3 Promise的实现原理回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.4 safelyResolveThen

坐标 6/50:3·1·4 safelyResolveThen。稳定证据键 NDBG-UNIT03-F。 第 3 章 代码把3·1·4 safelyResolveThen回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.5 doResolve和doReject

坐标 7/50:3·1·5 doResolve和doReject。稳定证据键 NDBG-UNIT03-G。 第 3 章 代码把3·1·5 doResolve和doReject回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.6 Promise.prototype.then和Promise.prototype.catch

坐标 8/50:3·1·6 Promise·prototype·then和Promise·prototype·catch。稳定证据键 NDBG-UNIT03-H。 第 3 章 代码把3·1·6 Promise·prototype·then和Promise·prototype·catch回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.7 值穿透

坐标 9/50:3·1·7 值穿透。稳定证据键 NDBG-UNIT03-I。 第 3 章 代码把3·1·7 值穿透回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.8 Promise.resolve和Promise.reject

坐标 10/50:3·1·8 Promise·resolve和Promise·reject。稳定证据键 NDBG-UNIT03-J。 第 3 章 代码把3·1·8 Promise·resolve和Promise·reject回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.9 Promise.all

坐标 11/50:3·1·9 Promise·all。稳定证据键 NDBG-UNIT03-K。 第 3 章 代码把3·1·9 Promise·all回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.10 Promise.race

坐标 12/50:3·1·10 Promise·race。稳定证据键 NDBG-UNIT03-L。 第 3 章 代码把3·1·10 Promise·race回到解决过程、thenable同化、状态不可逆、处理器缺省和值/错误传播;示例实现只用于观察语义,不替代当前ECMAScript规范。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.1.11 代码解析

坐标 13/50:3·1·11 代码解析。稳定证据键 NDBG-UNIT03-M。 第 3 章 代码把3·1·11 代码解析映射成症状、竞争假设、版本化原始工件、推翻条件和同输入恢复;目录名与工具输出都不直接等于根因。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2 Async Await

坐标 14/50:3·2 Async Await。稳定证据键 NDBG-UNIT03-N。 第 3 章 代码把3·2 Async Await映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2.1 例1:async await

坐标 15/50:3·2·1 例1:async await。稳定证据键 NDBG-UNIT03-O。 第 3 章 代码把3·2·1 例1:async await映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2.2 例2:co yield

坐标 16/50:3·2·2 例2:co yield。稳定证据键 NDBG-UNIT03-P。 第 3 章 代码把3·2·2 例2:co yield映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2.3 例3:co yield*

坐标 17/50:3·2·3 例3:co yield*。稳定证据键 NDBG-UNIT03-Q。 第 3 章 代码把3·2·3 例3:co yield*映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2.4 例4:co bluebird

坐标 18/50:3·2·4 例4:co bluebird。稳定证据键 NDBG-UNIT03-R。 第 3 章 代码把3·2·4 例4:co bluebird映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2.5 从yield转为yield*遇到的坑

坐标 19/50:3·2·5 从yield转为yield*遇到的坑。稳定证据键 NDBG-UNIT03-S。 第 3 章 代码把3·2·5 从yield转为yield*遇到的坑映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.2.6 async bluebird

坐标 20/50:3·2·6 async bluebird。稳定证据键 NDBG-UNIT03-T。 第 3 章 代码把3·2·6 async bluebird映射为Promise链、生成器委托、微任务与错误传播;原作co/Bluebird性能案例固定在Node 8,不外推到当前V8。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3 Error Stack

坐标 21/50:3·3 Error Stack。稳定证据键 NDBG-UNIT03-U。 第 3 章 代码把3·3 Error Stack保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.1 Stack Trace

坐标 22/50:3·3·1 Stack Trace。稳定证据键 NDBG-UNIT03-V。 第 3 章 代码把3·3·1 Stack Trace保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.2 Error.captureStackTrace

坐标 23/50:3·3·2 Error·captureStackTrace。稳定证据键 NDBG-UNIT03-W。 第 3 章 代码把3·3·2 Error·captureStackTrace保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.3 captureStackTrace在Mongolass中的应用

坐标 24/50:3·3·3 captureStackTrace在Mongolass中的应用。稳定证据键 NDBG-UNIT03-X。 第 3 章 代码把3·3·3 captureStackTrace在Mongolass中的应用保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.4 Error.prepareStackTrace

坐标 25/50:3·3·4 Error·prepareStackTrace。稳定证据键 NDBG-UNIT03-Y。 第 3 章 代码把3·3·4 Error·prepareStackTrace保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.5 Error.prepareStackTrace的其他用法

坐标 26/50:3·3·5 Error·prepareStackTrace的其他用法。稳定证据键 NDBG-UNIT03-Z。 第 3 章 代码把3·3·5 Error·prepareStackTrace的其他用法保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.6 Error.stackTraceLimit

坐标 27/50:3·3·6 Error·stackTraceLimit。稳定证据键 NDBG-UNIT03-AA。 第 3 章 代码把3·3·6 Error·stackTraceLimit保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.3.7 Long Stack Trace

坐标 28/50:3·3·7 Long Stack Trace。稳定证据键 NDBG-UNIT03-AB。 第 3 章 代码把3·3·7 Long Stack Trace保存原始Error、cause/上下文、同步栈、异步传播身份和source map;格式化后的长栈不能取代首错与结构化错误字段。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4 node@8

坐标 29/50:3·4 node@8。稳定证据键 NDBG-UNIT03-AC。 第 3 章 代码把3·4 node@8限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.1 Ignition TurboFan

坐标 30/50:3·4·1 Ignition TurboFan。稳定证据键 NDBG-UNIT03-AD。 第 3 章 代码把3·4·1 Ignition TurboFan限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.2 版本的对应关系

坐标 31/50:3·4·2 版本的对应关系。稳定证据键 NDBG-UNIT03-AE。 第 3 章 代码把3·4·2 版本的对应关系映射成症状、竞争假设、版本化原始工件、推翻条件和同输入恢复;目录名与工具输出都不直接等于根因。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.3 try/catch

坐标 32/50:3·4·3 try/catch。稳定证据键 NDBG-UNIT03-AF。 第 3 章 代码把3·4·3 try/catch限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.4 delete

坐标 33/50:3·4·4 delete。稳定证据键 NDBG-UNIT03-AG。 第 3 章 代码把3·4·4 delete限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.5 arguments

坐标 34/50:3·4·5 arguments。稳定证据键 NDBG-UNIT03-AH。 第 3 章 代码把3·4·5 arguments限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.6 async性能提升

坐标 35/50:3·4·6 async性能提升。稳定证据键 NDBG-UNIT03-AI。 第 3 章 代码把3·4·6 async性能提升限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.4.7 不会优化的特性

坐标 36/50:3·4·7 不会优化的特性。稳定证据键 NDBG-UNIT03-AJ。 第 3 章 代码把3·4·7 不会优化的特性限定为Node 8.9.4与当时V8优化管线的实验结论;当前轨道重新基准,不把历史“优化禁忌”写成永久语言规则。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.5 Rust Addons

坐标 37/50:3·5 Rust Addons。稳定证据键 NDBG-UNIT03-AK。 第 3 章 代码把3·5 Rust Addons分开Rust语言边界、FFI封装、Neon版本和Node-API ABI保证;外部库、libuv与V8直接接口不自动获得ABI稳定性。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.5.1 Rust

坐标 38/50:3·5·1 Rust。稳定证据键 NDBG-UNIT03-AL。 第 3 章 代码把3·5·1 Rust分开Rust语言边界、FFI封装、Neon版本和Node-API ABI保证;外部库、libuv与V8直接接口不自动获得ABI稳定性。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.5.2 FFI

坐标 39/50:3·5·2 FFI。稳定证据键 NDBG-UNIT03-AM。 第 3 章 代码把3·5·2 FFI分开Rust语言边界、FFI封装、Neon版本和Node-API ABI保证;外部库、libuv与V8直接接口不自动获得ABI稳定性。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.5.3 Neon

坐标 40/50:3·5·3 Neon。稳定证据键 NDBG-UNIT03-AN。 第 3 章 代码把3·5·3 Neon分开Rust语言边界、FFI封装、Neon版本和Node-API ABI保证;外部库、libuv与V8直接接口不自动获得ABI稳定性。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.5.4 NAPI

坐标 41/50:3·5·4 NAPI。稳定证据键 NDBG-UNIT03-AO。 第 3 章 代码把3·5·4 NAPI分开Rust语言边界、FFI封装、Neon版本和Node-API ABI保证;外部库、libuv与V8直接接口不自动获得ABI稳定性。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.6 Event Loop

坐标 42/50:3·6 Event Loop。稳定证据键 NDBG-UNIT03-AP。 第 3 章 代码把3·6 Event Loop绑定libuv阶段、微任务/nextTick队列、活跃句柄、event-loop utilization与delay;单次回调顺序不能代表稳态负载。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.6.1 什么是Event Loop

坐标 43/50:3·6·1 什么是Event Loop。稳定证据键 NDBG-UNIT03-AQ。 第 3 章 代码把3·6·1 什么是Event Loop绑定libuv阶段、微任务/nextTick队列、活跃句柄、event-loop utilization与delay;单次回调顺序不能代表稳态负载。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.6.2 poll阶段

坐标 44/50:3·6·2 poll阶段。稳定证据键 NDBG-UNIT03-AR。 第 3 章 代码把3·6·2 poll阶段绑定libuv阶段、微任务/nextTick队列、活跃句柄、event-loop utilization与delay;单次回调顺序不能代表稳态负载。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.6.3 process.nextTick()

坐标 45/50:3·6·3 process·nextTick()。稳定证据键 NDBG-UNIT03-AS。 第 3 章 代码把3·6·3 process·nextTick()绑定libuv阶段、微任务/nextTick队列、活跃句柄、event-loop utilization与delay;单次回调顺序不能代表稳态负载。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.6.4 代码解析

坐标 46/50:3·6·4 代码解析。稳定证据键 NDBG-UNIT03-AT。 第 3 章 代码把3·6·4 代码解析映射成症状、竞争假设、版本化原始工件、推翻条件和同输入恢复;目录名与工具输出都不直接等于根因。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.7 处理uncaughtException

坐标 47/50:3·7 处理uncaughtException。稳定证据键 NDBG-UNIT03-AU。 第 3 章 代码把3·7 处理uncaughtException将未捕获异常视为进程状态可能不可信的终止边界,并为ReDoS记录输入规模、同步阻塞与超时;监听器主要用于同步清理和退出。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.7.1 uncaughtException

坐标 48/50:3·7·1 uncaughtException。稳定证据键 NDBG-UNIT03-AV。 第 3 章 代码把3·7·1 uncaughtException将未捕获异常视为进程状态可能不可信的终止边界,并为ReDoS记录输入规模、同步阻塞与超时;监听器主要用于同步清理和退出。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.7.2 使用llnode

坐标 49/50:3·7·2 使用llnode。稳定证据键 NDBG-UNIT03-AW。 第 3 章 代码把3·7·2 使用llnode绑定PID、可执行文件、Node/V8构建、平台、core限制与符号;转储可能含密钥和用户数据,只能在隔离、加密、限权流程中处理。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

3.7.3 ReDoS

坐标 50/50:3·7·3 ReDoS。稳定证据键 NDBG-UNIT03-AX。 第 3 章 代码把3·7·3 ReDoS将未捕获异常视为进程状态可能不可信的终止边界,并为ReDoS记录输入规模、同步阻塞与超时;监听器主要用于同步清理和退出。 第 3 章 代码在该坐标必须记录症状输入、竞争假设、进程/构建身份、采集参数、原始工件、首个分岔、推翻条件和恢复结果;工具截图、自动建议或综合分数都不能单独证明根因。

三个可操作证据视图

第 3 章 代码先预测:只注入“把最终uncaughtException监听器当成可继续运行的恢复机制”时,指标、CPU/堆工件、异步事件、trace或报警中哪一类最先偏离?先选正式坐标和时代轨道,再重放参考、故障、恢复并打开迁移安全门。

分步1 / 3

假设阶梯:从症状缩小到可推翻结论

症状—假设—证据阶梯

第 3 章 代码

从可复现症状出发,逐层缩小到能被原始工件推翻的假设。

作者原仓库历史复现 · 坐标 1/50

冻结症状与输入

待证伪假设
第 3 章 代码先把“错误栈断裂、请求挂起或吞吐在代码变更后下降”写成可重复条件,不预设工具结论
采集工件
用户时间线、固定请求集、并发、数据、启动/预热与成功判据
身份标签
Node 8.9.4、V8、Ubuntu 16.04、依赖锁与作者仓库固定提交
推翻条件
同输入不能稳定重现症状,或基线自身漂移超过故障差分

最小可重复诊断协议

  1. 第 3 章 代码冻结请求集、数据、并发、预热、成功率/延迟、Node/V8、依赖锁、构建哈希、主机/容器、时钟和采集预算。
  2. 第 3 章 代码先保存低扰动基线,再逐层升级到profile、heap/core、trace或调试会话;每份工件记录PID、起始/结束、参数、哈希和访问级别。
  3. 第 3 章 代码保持其余条件不变,只注入“把最终uncaughtException监听器当成可继续运行的恢复机制”,用至少两类独立工件寻找首个分岔并保留竞争性解释。
  4. 第 3 章 代码撤销变量或最小修复后以同一输入重放;无法满足“代码诊断必须保留原始错误、异步上下文、队列阶段、Node/V8身份和安全退出”时,结论必须标为失败或未知。

小结与上架门

第 3 章 代码的核心不是记住更多调试工具,而是把Promise、Async/Await、Error Stack、Node 8、Rust Addons、Event Loop与uncaughtException纳入同一条可证伪链:作者仓库准确限定原作,运行时/维护方文档限定当前能力,症状合同约束输入,原始工件与三角校验定位首错,迁移门、数据安全和同输入恢复决定结论能否发布。最终交付最小复现、结构化错误链、async上下文轨迹、event-loop信号、addon ABI矩阵和退出日志并报告失败、未知项与采集扰动。

练习与答案

练习

问题 1:第3章 代码

为第 3 章 代码的稳定证据键 NDBG-UNIT03-A 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明第3章 代码在Node 8.9.4与当前Node之间的迁移边界。

问题 2:3.1 Promise

为第 3 章 代码的稳定证据键 NDBG-UNIT03-B 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1 Promise在Node 8.9.4与当前Node之间的迁移边界。

问题 3:3.1.1 Promise/A规范

为第 3 章 代码的稳定证据键 NDBG-UNIT03-C 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·1 Promise/A规范在Node 8.9.4与当前Node之间的迁移边界。

问题 4:3.1.2 从零开始实现Promise

为第 3 章 代码的稳定证据键 NDBG-UNIT03-D 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·2 从零开始实现Promise在Node 8.9.4与当前Node之间的迁移边界。

问题 5:3.1.3 Promise的实现原理

为第 3 章 代码的稳定证据键 NDBG-UNIT03-E 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·3 Promise的实现原理在Node 8.9.4与当前Node之间的迁移边界。

问题 6:3.1.4 safelyResolveThen

为第 3 章 代码的稳定证据键 NDBG-UNIT03-F 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·4 safelyResolveThen在Node 8.9.4与当前Node之间的迁移边界。

问题 7:3.1.5 doResolve和doReject

为第 3 章 代码的稳定证据键 NDBG-UNIT03-G 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·5 doResolve和doReject在Node 8.9.4与当前Node之间的迁移边界。

问题 8:3.1.6 Promise.prototype.then和Promise.prototype.catch

为第 3 章 代码的稳定证据键 NDBG-UNIT03-H 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·6 Promise·prototype·then和Promise·prototype·catch在Node 8.9.4与当前Node之间的迁移边界。

问题 9:3.1.7 值穿透

为第 3 章 代码的稳定证据键 NDBG-UNIT03-I 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·7 值穿透在Node 8.9.4与当前Node之间的迁移边界。

问题 10:3.1.8 Promise.resolve和Promise.reject

为第 3 章 代码的稳定证据键 NDBG-UNIT03-J 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·8 Promise·resolve和Promise·reject在Node 8.9.4与当前Node之间的迁移边界。

问题 11:3.1.9 Promise.all

为第 3 章 代码的稳定证据键 NDBG-UNIT03-K 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·9 Promise·all在Node 8.9.4与当前Node之间的迁移边界。

问题 12:3.1.10 Promise.race

为第 3 章 代码的稳定证据键 NDBG-UNIT03-L 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·10 Promise·race在Node 8.9.4与当前Node之间的迁移边界。

问题 13:3.1.11 代码解析

为第 3 章 代码的稳定证据键 NDBG-UNIT03-M 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·1·11 代码解析在Node 8.9.4与当前Node之间的迁移边界。

问题 14:3.2 Async Await

为第 3 章 代码的稳定证据键 NDBG-UNIT03-N 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2 Async Await在Node 8.9.4与当前Node之间的迁移边界。

问题 15:3.2.1 例1:async await

为第 3 章 代码的稳定证据键 NDBG-UNIT03-O 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2·1 例1:async await在Node 8.9.4与当前Node之间的迁移边界。

问题 16:3.2.2 例2:co yield

为第 3 章 代码的稳定证据键 NDBG-UNIT03-P 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2·2 例2:co yield在Node 8.9.4与当前Node之间的迁移边界。

问题 17:3.2.3 例3:co yield*

为第 3 章 代码的稳定证据键 NDBG-UNIT03-Q 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2·3 例3:co yield*在Node 8.9.4与当前Node之间的迁移边界。

问题 18:3.2.4 例4:co bluebird

为第 3 章 代码的稳定证据键 NDBG-UNIT03-R 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2·4 例4:co bluebird在Node 8.9.4与当前Node之间的迁移边界。

问题 19:3.2.5 从yield转为yield*遇到的坑

为第 3 章 代码的稳定证据键 NDBG-UNIT03-S 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2·5 从yield转为yield*遇到的坑在Node 8.9.4与当前Node之间的迁移边界。

问题 20:3.2.6 async bluebird

为第 3 章 代码的稳定证据键 NDBG-UNIT03-T 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·2·6 async bluebird在Node 8.9.4与当前Node之间的迁移边界。

问题 21:3.3 Error Stack

为第 3 章 代码的稳定证据键 NDBG-UNIT03-U 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3 Error Stack在Node 8.9.4与当前Node之间的迁移边界。

问题 22:3.3.1 Stack Trace

为第 3 章 代码的稳定证据键 NDBG-UNIT03-V 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·1 Stack Trace在Node 8.9.4与当前Node之间的迁移边界。

问题 23:3.3.2 Error.captureStackTrace

为第 3 章 代码的稳定证据键 NDBG-UNIT03-W 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·2 Error·captureStackTrace在Node 8.9.4与当前Node之间的迁移边界。

问题 24:3.3.3 captureStackTrace在Mongolass中的应用

为第 3 章 代码的稳定证据键 NDBG-UNIT03-X 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·3 captureStackTrace在Mongolass中的应用在Node 8.9.4与当前Node之间的迁移边界。

问题 25:3.3.4 Error.prepareStackTrace

为第 3 章 代码的稳定证据键 NDBG-UNIT03-Y 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·4 Error·prepareStackTrace在Node 8.9.4与当前Node之间的迁移边界。

问题 26:3.3.5 Error.prepareStackTrace的其他用法

为第 3 章 代码的稳定证据键 NDBG-UNIT03-Z 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·5 Error·prepareStackTrace的其他用法在Node 8.9.4与当前Node之间的迁移边界。

问题 27:3.3.6 Error.stackTraceLimit

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AA 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·6 Error·stackTraceLimit在Node 8.9.4与当前Node之间的迁移边界。

问题 28:3.3.7 Long Stack Trace

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AB 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·3·7 Long Stack Trace在Node 8.9.4与当前Node之间的迁移边界。

问题 29:3.4 node@8

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AC 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4 node@8在Node 8.9.4与当前Node之间的迁移边界。

问题 30:3.4.1 Ignition TurboFan

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AD 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·1 Ignition TurboFan在Node 8.9.4与当前Node之间的迁移边界。

问题 31:3.4.2 版本的对应关系

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AE 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·2 版本的对应关系在Node 8.9.4与当前Node之间的迁移边界。

问题 32:3.4.3 try/catch

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AF 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·3 try/catch在Node 8.9.4与当前Node之间的迁移边界。

问题 33:3.4.4 delete

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AG 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·4 delete在Node 8.9.4与当前Node之间的迁移边界。

问题 34:3.4.5 arguments

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AH 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·5 arguments在Node 8.9.4与当前Node之间的迁移边界。

问题 35:3.4.6 async性能提升

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AI 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·6 async性能提升在Node 8.9.4与当前Node之间的迁移边界。

问题 36:3.4.7 不会优化的特性

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AJ 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·4·7 不会优化的特性在Node 8.9.4与当前Node之间的迁移边界。

问题 37:3.5 Rust Addons

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AK 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·5 Rust Addons在Node 8.9.4与当前Node之间的迁移边界。

问题 38:3.5.1 Rust

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AL 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·5·1 Rust在Node 8.9.4与当前Node之间的迁移边界。

问题 39:3.5.2 FFI

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AM 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·5·2 FFI在Node 8.9.4与当前Node之间的迁移边界。

问题 40:3.5.3 Neon

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AN 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·5·3 Neon在Node 8.9.4与当前Node之间的迁移边界。

问题 41:3.5.4 NAPI

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AO 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·5·4 NAPI在Node 8.9.4与当前Node之间的迁移边界。

问题 42:3.6 Event Loop

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AP 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·6 Event Loop在Node 8.9.4与当前Node之间的迁移边界。

问题 43:3.6.1 什么是Event Loop

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AQ 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·6·1 什么是Event Loop在Node 8.9.4与当前Node之间的迁移边界。

问题 44:3.6.2 poll阶段

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AR 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·6·2 poll阶段在Node 8.9.4与当前Node之间的迁移边界。

问题 45:3.6.3 process.nextTick()

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AS 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·6·3 process·nextTick()在Node 8.9.4与当前Node之间的迁移边界。

问题 46:3.6.4 代码解析

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AT 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·6·4 代码解析在Node 8.9.4与当前Node之间的迁移边界。

问题 47:3.7 处理uncaughtException

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AU 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·7 处理uncaughtException在Node 8.9.4与当前Node之间的迁移边界。

问题 48:3.7.1 uncaughtException

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AV 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·7·1 uncaughtException在Node 8.9.4与当前Node之间的迁移边界。

问题 49:3.7.2 使用llnode

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AW 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·7·2 使用llnode在Node 8.9.4与当前Node之间的迁移边界。

问题 50:3.7.3 ReDoS

为第 3 章 代码的稳定证据键 NDBG-UNIT03-AX 设计一个固定症状、两个竞争假设、两类独立工件、一个单变量故障和一个恢复断言,并说明3·7·3 ReDoS在Node 8.9.4与当前Node之间的迁移边界。

问题 51:为什么完整作者仓库仍不能直接复制

第 3 章 代码已经能访问作者公开全文,为什么仍采用独立重构?

问题 52:为什么要三角校验

第 3 章 代码为什么不能只靠一个火焰图、heap snapshot、APM页面或报警裁决?

六个诊断裁决术语

第 3 章 代码使用构成最小证据语言;每个术语都绑定真实输入、状态和工件,不制造置信度、根因分或装饰性排名。

名词解释

本章出现的专业名词,用大白话再讲一遍。

症状合同

第 3 章 代码中固定用户现象、请求、数据、时序和成功判据的复现声明。

竞争假设

第 3 章 代码中至少两个能解释同一症状且可分别推翻的根因候选。

原始工件

第 3 章 代码中带版本、参数、时间、进程身份和哈希的profile、snapshot、core、trace或事件文件。

采集扰动

第 3 章 代码中诊断工具对CPU、事件循环、内存、磁盘、网络与行为的改变。

首个分岔

第 3 章 代码的故障轨迹最早偏离同输入参考轨迹的位置。

迁移差分

第 3 章 代码把Node 8.9.4工具身份映射到当前受支持能力的显式变化表。

资料与写作方式声明

本章以赵坤《Node.js调试指南(全彩)》权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…