fast-check 3.9.0 发布解读:细粒度 `act` 让竞态条件检测更精准

发布时间:2026/10/13 6:05:01

fast-check 3.9.0 发布解读:细粒度 `act` 让竞态条件检测更精准 开发工具测试【免费下载链接】fast-checkProperty based testing framework for JavaScript (like QuickCheck) written in TypeScript项目地址https://gitcode.com/gh_mirrors/fa/fast-check点击查看免费下载本篇技术指南围绕 fast-check 3.9.0 版本的核心更新展开它把调度器fc.scheduler的act包装能力从全局唯一细化为按任务定义、按等待释放两级局部控制并修复了超时取值越界与scheduledModelRun无限等待两个关键缺陷。读完本文你将掌握三级act包裹的实际调用链、在 React 组件测试与原生定时器场景中的落地写法以及竞态条件检测与模型化测试组合使用的完整姿势。版本定位3.9.0 的发布主题3.9.0 是 fast-check 3.x 生命周期中的一个功能型小版本基于 3.8.3覆盖自 3.8.0 以来的全部变更发布主题在仓库 CHANGELOG_3.X.md 中被概括为 Finer definition ofactto detect race conditions——即围绕act的更细粒度定义来增强竞态条件检测能力。其两大特性PR#3889、PR#3890分别对应在调度任务定义时per-call传入自定义act在释放任务时per-wait传入自定义act。配合两项 bug 修复超时上限截断、调度模型无限循环以及同期文档体系向 Docusaurus 的大规模迁移共同构成了本次发布的全貌。一、Local act把act从全局下沉到局部1.1 act 的由来React 测试中的竞态检测痛点act选项最初的设计目的是在对 React 组件/ Hook 做竞态条件测试时把触发状态更新的 Promise 解析包进act(...)上下文。否则 React 会输出如下警告Warning: An update to TestComponent inside a test was not wrapped in act(...). When testing, code that causes React state updates should be wrapped into act(...): act(() { /* fire events that update state */ }); /* assert on the output */ This ensures that youre testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act这类警告很容易在手动控制 Promise 的解析时机时被触发。原文档给出的典型场景是测试以最后一个 Promise 的值为准的 Hook其中resolve2(2)一旦执行就会立刻触发状态更新若不将其包进act警告就会出现function usePromiseAsState(promise) { const [value, setValue] useState(undefined); useEffect(() { let canceled false; setValue(undefined); promise.then( (value) !canceled setValue(value), () {}, ); return () (canceled true); }, [promise]); return value; }对应测试test(should update to the value of the last promise, async () { let resolve1 null; let resolve2 null; const promise1 new Promise((r) (resolve1 r)); const promise2 new Promise((r) (resolve2 r)); const { result, rerender } renderHook((p) usePromiseAsState(p), { initialProps: promise1, }); rerender(promise2); expect(result.current).toBe(undefined); await act(async () { resolve1(1); }); expect(result.current).toBe(undefined); await act(async () { resolve2(2); }); expect(result.current).toBe(2); });既然 fast-check 要把竞态检测能力延伸到 React 代码就必须让用户能方便地声明如何包装解析过程这就是act支持存在的理由。1.2 新 API按任务、按等待两级局部act从 2.2.0 起fc.scheduler已经支持在创建时传入全局act见 scheduler 的约束定义。3.9.0 之前的问题在于act只能设在调度器这一层无法针对单个任务或单次等待差异化定制。3.9.0 把act能力下沉到了schedule系与wait系方法上。先看新引入的类型SchedulerAct定义于 Scheduler.ts/** * Function responsible to run the passed function and surround it with whatever needed. * The name has been inspired from the act function coming with React. * * This wrapper function is not supposed to throw. The received function f will never throw. */ export type SchedulerAct (f: () Promisevoid) Promisevoid;从类型签名可以看出act是一个接收一个待执行函数、用自己的上下文包住它的包装器fast-check 保证传入的f永不抛出因此act内部无需处理异常分支。配套地Scheduler接口中所有涉及任务入队与释放的方法都增加了customAct参数见 Scheduler.tsscheduleT(task, label?, metadata?, customAct?)—— 包装单个 Promise 时指定actscheduleFunction(asyncFunction, customAct?)—— 包装产出 Promise 的 API时指定actscheduleSequence(sequenceBuilders, customAct?)—— 包装一组顺序任务时指定actwaitNext(count, customAct?)、waitIdle(customAct?)、waitFor(task, customAct?)—— 等待释放时指定act已废弃的waitOne(customAct?)、waitAll(customAct?)同样保留该参数waitAll自 4.2.0 起推荐改用waitIdle。注意schedulerForfc.schedulerFor([1,3,2])这类硬编码顺序的调度器同样接受act约束——它最终通过 BuildSchedulerFor.ts 把act传给SchedulerImplem构造。1.3 三种用法调度级、等待级、任务级原文档给出了三种使用方式的完整对比这里逐一展开。用法 A任务级act3.9.0 新增推荐。每个任务在定义时各自声明包装方式。React 场景下schedule的第 4 个参数直接传acttest(should update to the value of the last promise, async () { await fc.assert( fc.property(fc.scheduler(), async (s) { const promise1 s.schedule(Promise.resolve(1), undefined, undefined, act); const promise2 s.schedule(Promise.resolve(2), undefined, undefined, act); const { result, rerender } renderHook((p) usePromiseAsState(p), { initialProps: promise1, }); rerender(promise2); expect(result.current).toBe(undefined); await s.waitAll(); expect(result.current).toBe(2); }), ); });若使用历史 API上例中的fc.property 异步谓词需写作fc.asyncProperty从当前仓库 Property.ts 的类型注释看property已直接支持异步谓词asyncProperty是早期版本的历史形态。用法 B等待级act3.9.0 新增。如果所有任务希望被同一种方式包装可以只在释放时统一传入把s.schedule(..., undefined, undefined, act)改回s.schedule(...)再把s.waitAll()换成s.waitAll(act)现代写法对应s.waitIdle(act)或s.waitNext(count, act)。用法 C调度器级act老方案不再推荐。这是 3.9.0 之前唯一可用的方式即在fc.scheduler({ act })创建时全局指定。原文档明确提示在手工编写复现示例custom manual examples时这种方案要求你把自定义act同样传给手工创建的fc.schedulerFor实例——虽然支持但很容易忘记因此建议优先采用等待级或任务级写法。1.4 源码视角三级act的包裹顺序从 SchedulerImplem.ts 的实现可以看到三级act是如何叠加的。接口注释给出了权威的包裹顺序全局act定义在fc.scheduler上包裹等待层等待级act定义在s.waitX(...)上包裹局部层任务级act定义在s.scheduleX(...)上包裹触发函数。落到实现上scheduleInternal会把customAct || defaultSchedulerAct存入ScheduledTask.customActSchedulerImplem.ts默认值是恒等包装(f) f()同文件第 7 行。释放任务时internalWaitOne取出该任务并执行scheduledTask.customAct(() ...trigger())SchedulerImplem.ts而waitOne又把整个等待动作包进this.act(...)同文件第 233-237 行waitOne(customAct?: SchedulerAct): Promisevoid { const waitAct customAct || defaultSchedulerAct; const waitOneResult: Promiseunknown this.act(() waitAct(() this.internalWaitOne())); return waitOneResult as Promisevoid; }因此一次任务释放的实际执行路径是全局act→ 等待级act→ 任务级act→ 触发原 Promise。waitNext、waitIdle、waitFor同样通过internalWaitFor把customAct传导到每次waitOne调用SchedulerImplem.ts即按等待定制在内部等价于对该轮释放的所有任务施加同一act。这些行为在SchedulerImplem.spec.ts中有大量单测覆盖如 waitFor 相关用例位于 SchedulerImplem.spec.ts。1.5 不限于 React用act调度原生定时器act模式并非 React 专属。原文档特别指出凡需要为调用引入特定上下文的场景都适用。最典型的例子是调度原生定时器——setTimeout/setInterval是有序的10ms 的定时器一定先于 100ms 的定时器触发与调度器任意重排 Promise 解析顺序的机制天然冲突需要特殊处理。官方文档 race-conditions.md 给出了一个基于 Jest fake timers 的act实现通过s.schedule(Promise.resolve(advance timers))把推进定时器本身变成调度任务并在任务解析后递归检测新增定时器从而让定时器也纳入调度器的控制之下。使用时将act传给等待方法即可// Instead of calling await s.waitFor(p), you can call await s.waitFor(p, buildWrapWithTimersAct(s)). // Instead of calling await s.waitIdle(), you can call await s.waitIdle(buildWrapWithTimersAct(s)).这正是 3.9.0 两级局部act的直接受益场景定时器act只需作用于等待层无需污染调度器上其他任务的包装策略。二、两个关键 Bug 修复2.1 超时上限0x7fffffff截断修复前凡是大于0x7fffffff即2^31 - 1约 24.8 天的超时值都会被setTimeout等宿主函数静默折算最终被降级为0导致本以为会等待很久、实际立即触发的意外行为。3.9.0 在内部对超时取值做了上限截断PR#3892记录于 CHANGELOG_3.X.md避免超长超时参数进入setTimeout后被运行时换算成不可预期的结果。顺带一提0x7fffffff在 fast-check 中也承担未显式指定时的最大值这一语义例如integer、nat的默认上界以及字符串/数组/字典类 arbitrary 的maxLength默认值见 MaxLengthFromMinLength.ts 与 integer.ts。理解这一常量在仓库中的双重含义有助于读懂报错日志里出现的0x7fffffff。2.2 调度模型无限循环scheduledModelRun不再卡死fc.scheduledModelRun用于把模型化测试model-based testing与调度器结合让模型的执行过程也经过调度器重排。修复前存在一类缺陷模型有时会陷入无限等待——调度器在等模型执行而模型又在等调度器释放任务二者互相等待、谁都到不了终点。从当前实现看ModelRunner.ts 中scheduledModelRun的收尾逻辑已经非常明确export async function scheduledModelRun(...) { const scheduledCommands scheduleCommands(scheduler, cmds); const out internalAsyncModelRun(s, scheduledCommands, scheduler.schedule(Promise.resolve(), startModel)); await scheduler.waitFor(out); await scheduler.waitAll(); }这里有三层保证先把所有命令通过scheduleCommands生成器逐个包装为ScheduledCommand见 ScheduledCommand.ts对应单测在 ScheduledCommand.spec.ts随后用scheduler.schedule(Promise.resolve(), startModel)把模型启动本身注册为一个调度任务确保运行推进必须经由调度器最后先用waitFor(out)等到模型整体结束再用waitAll()清空余下的全部任务。正是始终把模型调度到最后一刻Always schedule models until the endPR#3887这一修复杜绝了模型运行中途因缺少任务释放而无限等待的情况。需要提醒的是官方文档 race-conditions.md 同时强调模型内的check/run不应依赖其他已调度任务的完成来达成自身目标——它们可以触发新的调度任务但不能等待这些任务解析否则仍可能重新引入死锁式的互相等待。三、自 3.8.0 以来的变更全览3.9.0 基于 3.8.3本节梳理自 3.8.0 起的功能与修复含 3.8.13.8.3 的累积变更。3.1 FeaturesPR变更PR#3889增加按调用per call定制act的能力PR#3890增加按等待per wait定制act的能力3.2 Fixes 中的关键项PR变更PR#3892Bug将超时值截断至0x7fff_ffffPR#3887Bug始终将模型调度到执行结束修复无限循环PR#3880CI稳定jsonValue上的测试PR#3876Clean移除遗留文档PR#3875Doc发布关于切换到 Docusaurus 的第一篇博客3.3 文档体系重构迁移至 Docusaurus3.8.x 到 3.9.0 期间fast-check 的文档工作几乎重构了一遍发布基础设施文档站点切换为 DocusaurusPR#3723、增加全文搜索PR#3734、统一链接到 fast-check.devPR#3755、补齐核心构建块core building blocks章节PR#3745、新增高级advanced部分PR#3800以及竞态条件教程PR#3820、PR#3834、PR#3836 等。随版本发布的 race conditions 教程与配套调度器文档正是本期文档工作的直接产物——相关权威内容现在沉淀在 race-conditions.md其中对Scheduler全部方法schedule、scheduleFunction、scheduleSequence、waitNext、waitIdle、waitFor、report等的签名与用法说明可作为第一手参考资料。其余改动以工程化收尾为主CI 全部包统一发布PR#3775、文档部署流程调整PR#3728、PR#3732、包产物附加 provenance 安全凭证PR#3774、类型检查移除 parse5PR#3792等此处不再逐一展开。结语3.9.0 是一次小而准的发布act从调度器级下沉到任务级与等待级补齐了竞态检测在 React 场景和定时器场景下的最后一块拼图两个 bug 修复则消除了超长超时被静默降级、调度模型互相等待这类隐蔽陷阱。对正在使用fc.scheduler做异步竞态检测的团队升级后建议按本文 1.3 节的三种用法重新审视现有测试优先把act收敛到等待级或任务级让复现用例schedulerFor的编写不再受全局act约束。进一步深入可阅读仓库中的 Scheduler 接口定义、SchedulerImplem 实现 与 模型调度实现或参考官方竞态条件指南 race-conditions.md 完成从原理到实践的完整闭环。赞分享开发工具测试【免费下载链接】fast-checkProperty based testing framework for JavaScript (like QuickCheck) written in TypeScript项目地址https://gitcode.com/gh_mirrors/fa/fast-check点击查看免费下载相关推荐TinyGo并发分析竞态条件检测TinyGo并发分析竞态条件检测 引言 在嵌入式系统和微控制器开发中并发编程Concurrent Programming是提升系统性能和响应能力的关键技编译器嵌入式语言运行时WebAssembly用 fast-check 实例库学会寻找性质从纯函数、递归结构到状态机与竞态条件检测用 fast check 实例库学会寻找性质从纯函数、递归结构到状态机与竞态条件检测 导读 本文以 fast check 官方仓库中的 examples 实例开发工具测试RVC变声器终极指南10分钟快速上手解决所有常见问题RVC变声器终极指南10分钟快速上手解决所有常见问题 Retrieval based Voice Conversion WebUI简称RVC是一个基于V人工智能AI 应用语音音频深度学习上一篇Mujoco_Playground高级应用从仿真到部署的全流程实践下一篇immich移动备份后台自动上传黑科技创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/13 6:05:01

课程论文写作工具红黑榜,2026届避坑参考

课程论文怎么写才能省时省力又过审?这是每年期末季最扎心的问题。这篇红黑榜把市面上主流的辅助工具按实测体验分了类,红榜放心选,黑榜绕着走,帮你在有限时间内把分数稳稳攥在手里。 aibiye(笔耶ai)官网直达…

2026/10/13 6:05:01

课程论文生成器红黑榜:这些能选,这些别碰

又到课程论文集中提交的时段,不少学生开始琢磨用AI工具省点时间。市面上的课程论文生成器确实多,但真正能用的没几个。这篇从实测角度出发,把aibiye(笔耶ai)、AICheck、Passbug和几款常见工具放在一起比一比&#xff0…

2026/10/13 7:10:04

黑黄配色商务PPT模板设计实操:母版、版式与兼容性维护

简介:这款黑黄配色商务报告PPT模板专为职场商务汇报场景设计,适合需要快速制作工作概况、阶段成就、经验教训或阶段计划等内容的用户选用。模板以黑色为底、黄色高亮,兼顾稳重感与信息突出度,内置目录页、数据图表、图片展示页等常…

2026/10/13 7:10:04

Spring Boot自动配置机制:Spring.factories文件解析与实践

1. Spring.factories 文件解析与应用场景Spring.factories 是 Spring Boot 自动配置机制中的关键配置文件,它采用 Java 的 SPI(Service Provider Interface)机制实现模块化扩展。这个文件通常位于 META-INF 目录下,格式为键值对形…

2026/10/13 7:10:04

Crunch.py:纯Python密码字典生成器的原理与应用

简介:Crunch 密码列表生成器的 Python 实现,主要面向安全测试、渗透测试及密码恢复等需要快速生成自定义字典的场景。脚本支持通过 min/max 参数设定密码长度范围,并通过字符集或掩码方式控制生成规则,还提供后缀添加、输出重定向…

2026/10/13 7:10:04

1. 存储性能基础:IO模型与存储栈解析

存储性能的根基——IO模型和存储栈。说实话,我见过太多性能问题,根子都出在对这条IO路径的理解上。你想想看,一个请求从应用发出去,到最终落盘,中间要经过多少层?每一层都可能成为瓶颈。 1.1 IO模型:同步、异步与阻塞 先说说IO模型。我个人习惯把IO模型分成三类:阻塞…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑