尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Puppeteer Mapper 类型全解析:理解 Locator.map 的同步/异步映射机制与类型安全用法

Puppeteer Mapper 类型全解析:理解 Locator.map 的同步/异步映射机制与类型安全用法 Puppeteer Mapper 类型全解析理解 Locator.map 的同步/异步映射机制与类型安全用法【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer导读MapperFrom, To是 Puppeteer 中定义元素映射函数形态的公共类型别名它将任意值From映射为To并允许同步返回或异步返回。在 Puppeteer 的 Locator 体系中它是 Locator.map() 方法的参数类型是构建先定位、后变换、再断言链式查询流程的关键枢纽。读完本文你将掌握该类型的精确定义、其背后Awaitable的语义、map在浏览器上下文中的执行原理以及如何借助源码与测试理解它的重试与异常行为。Mapper 类型精确定义关联文档 puppeteer.mapper.md 给出了该类型的完整定义其源码位于 packages/puppeteer-core/src/api/locators/locators.tsexport type MapperFrom, To (value: From) AwaitableTo;逐部分拆解如下组成含义From映射的输入类型泛型参数。在使用方如LocatorT中通常对应被定位元素的类型TTo映射的输出类型泛型参数。决定映射后产物的类型value: Frommapper 函数接收一个输入值AwaitableTo返回类型既允许同步返回To也允许返回PromiseLikeTo如PromiseTo即 mapper 可以是同步函数也可以是异步函数需要强调的是这里的函数名是Mapper映射器而非 Selector。它表达的是纯变换语义输入一个值、产出一个新值本身不承担等待元素出现或过滤不匹配项的职责——等待与重试由 Locator 框架负责。支撑类型AwaitableMapper 的返回类型AwaitableTo由 Puppeteer 公共类型Awaitable定义见 puppeteer.awaitable.mdexport type AwaitableT T | PromiseLikeT;PromiseLikeT是 TypeScript 内置的最小 Promise 抽象只要对象具有then方法即可比PromiseT更宽松因此若 mapper 内部执行同步运算可以直接返回普通值例如element element.textContent若需要跨 realm 交互或执行异步操作可直接标记async或返回Promise例如async el await compute(el)两种写法的函数都满足MapperFrom, To的类型约束无需额外包装。Mapper 的主战场Locator.map()在 locators.ts 中Mapper被Locator的公共方法map消费mapTo(mapper: MapperT, To): LocatorTo { return new MappedLocator(this._clone(), handle { // SAFETY: TypeScript cannot deduce the type. return (handle as any).evaluateHandle(mapper); }); }一次典型的调用链改写自测试用例 test/src/locator.test.tsimport puppeteer from puppeteer; const browser await puppeteer.launch(); const page await browser.newPage(); await page.setContent(divtest/div); // 定位文本为 test 的元素再把元素映射为 clickable 属性值 const value await page .locator(::-p-text(test)) .map(element { return element.getAttribute(clickable); }) .wait(); await browser.close();要点说明map返回的不是值而是一个新的LocatorTo因此它可以继续参与 Locator 的链式调用wait、waitHandle、再次filter、再次map等直到真正被消费LocatorT中的T即 Mapper 的输入From。上例中定位器返回LocatorElementmapper 接收的element就是页面中真实匹配的 DOM 元素map的映射结果类型由返回值的类型推导无需手动标注Mapper泛型但当你单独抽出一个复用函数并需要显式标注时就可以像下面这样引用公共类型import type {Mapper} from puppeteer; const toClickable: MapperElement, string | null element { return element.getAttribute(clickable); };原理纵深mapper 在页面上下文执行失败会触发重试从 MappedLocator 的实现可以看清 map 在运行时到底做了什么export class MappedLocatorFrom, To extends DelegatedLocatorFrom, To { #mapper: HandleMapperFrom, To; constructor(base: LocatorFrom, mapper: HandleMapperFrom, To) { super(base); this.#mapper mapper; } override _wait(options?: ReadonlyActionOptions): ObservableHandleForTo { return this.delegate._wait(options).pipe( mergeMap(handle { return from(Promise.resolve(this.#mapper(handle, options?.signal))); }), ); } }结合这段实现可以从源码层面得出三个重要结论mapper 真正运行在页面浏览器上下文。Locator.map在构造MappedLocator时通过handle.evaluateHandle(mapper)把用户函数交给页面执行见 locators.ts因此 mapper 内部可以直接访问element.getAttribute、textContent、innerHTML等 DOM API——这正是测试用例中 mapper 能读取元素属性的原因。mapper 属于被序列化并注入页面的函数遵循 Puppeteer 关于函数序列化与参数传递的约束。每次重试都会重新执行 mapper。_wait委托给底层定位器获取句柄再通过mergeMap将每个句柄送入 mapper。当元素尚不存在或不满足前置条件时底层定位器会持续重试Puppeteer 的 Locator 会对对象未就绪导致的操作失败自动重试参见 Locator 类注释一旦拿到句柄就立刻执行当前 mapper 求值。内部实际接受的是HandleMapper而非直接使用Mapper。源码中MappedLocator保存的是内部类型 HandleMapperexport type HandleMapperFrom, To ( value: HandleForFrom, signal?: AbortSignal, ) AwaitableHandleForTo;公共 API 的MapperT, To与内部HandleMapperFrom, To的分工值得注意HandleMapper面向 JS 句柄、并额外携带AbortSignal以支持中止是 Locator 内部管道真正消费的形式而Mapper面向已定位出的值这种更直白的形态是暴露给使用者的类型契约。从源码结构看公共map正是通过把用户提供的Mapper包进一次evaluateHandle调用完成值级映射到句柄级映射的转换。映射结果的消费方式wait 与 waitHandlemap 之后的新LocatorTo依然具备完整的定位器能力其中最常用的是 wait() 与 waitHandle()。相关实现见 locators.tswaitHandle()返回PromiseHandleForTo把映射产物包装成 JSHandle 交给调用方适合继续在页面侧操作对象wait()基于waitHandle()并调用handle.jsonValue()拿到序列化后的值。文档与源码都明确指出这要求映射结果可被 JSON 序列化Note this requires the value to be JSON-serializable因此若 mapper 返回 DOM 节点、函数等不可序列化对象应改用waitHandle而非wait。与 filter 的组合先过滤后映射Mapper与 Locator 的另一个公共方法 filter 天然互补filter用谓词筛选内部对应 Predicate 相关实现见 locators.tsmap做形态变换二者可自由串联。测试 locator.test.ts 展示了典型用法const result page .locator(::-p-text(test)) .filter(element { return element.getAttribute(clickable) ! null; // 先筛出 clickable 存在的元素 }) .map(element { return element.getAttribute(clickable); // 再映射为属性值 }) .wait(); await expect(result).resolves.toEqual(true);组合逻辑清晰定位器 →filter表达只保留满足条件的元素 →map表达把元素变换为业务需要的形态 →wait表达等到就绪并取值。异常即未就绪用测试理解重试语义测试 locator.test.ts 中有一个值得关注的用例 should work with throwsmapper 在元素缺少clickable属性时主动throw随后页面才被补上该属性最终wait()依然解析成功。它印证了 Locator 的核心行为——mapper 内抛出的错误会被当作元素尚未就绪的信号触发整个定位流程重试直到条件满足或超时。这为编写等到元素达到某状态再取值的自动化逻辑提供了范式与其在循环里手动轮询不如让 mapper 主动抛错、交由 Locator 的重试机制收敛。适用前提与注意事项运行前提Mapper相关 API 属公共类型随puppeteer与puppeteer-core一起发布map方法在基于Page/Frame创建的 Locator 上可用配合::-p-text、::-p-aria等选择器及普通 CSS 选择器均可使用。取值限制map(...).wait()要求映射结果为 JSON 可序列化值需要保留对象/句柄时应改用waitHandle。执行位置mapper 函数体在页面上下文执行可访问 DOM但不应依赖 Node 侧闭包变量函数将被序列化注入页面。类型形态公共层使用MapperFrom, To内部句柄管道使用HandleMapperFrom, To内部类型见 locators.ts理解二者区别有助于读懂 Locator 源码与排查类型推导问题。延伸阅读Locator.map() API 文档本类型唯一公共消费方法的完整签名与参数说明Awaitable 类型定义Mapper 返回类型的底层语义Locator 源码MapperL1019、HandleMapperL1023、MappedLocatorL1030、map()L751的完整实现Locator.map 测试用例正常映射、抛错重试、与 filter 组合三类行为验证【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表