ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Angular 如何用 httpResource 进行响应式数据请求并自动取消过期请求?

Angular 如何用 httpResource 进行响应式数据请求并自动取消过期请求? Angular 如何用 httpResource 进行响应式数据请求并自动取消过期请求【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular在 Angular 应用中常见的需求是根据某个响应式输入例如当前选中的userId向后端拉取数据输入一变就自动重新请求而且不能出现旧请求晚到、覆盖新数据的竞态。httpResource就是为这个场景设计的它是构建在HttpClient之上的响应式请求 API把请求状态和响应数据暴露为 signal 集合依赖的 signal 变化时自动发起新请求并在新请求发出前取消尚未完成的旧请求。该 API 从 Angular 22.0 起公开源码中标注publicApi 22.0见 resource.ts 与 resource_api.ts。版本前提上HttpClient 配置指南 说明HttpClient在 Angular v21 及以后默认可注入因此 Angular 22 的应用不需要额外配置就能使用httpResource。准备条件确认 HttpClient 可用httpResource使用全局的HttpClient实例发请求。官方指南http-resource.md给出的建议是不需要 HTTP 特性配置时直接调用httpResource即可无需provideHttpClient(...)只有需要配置拦截器interceptors或 XSRF 选项等 HTTP 特性时才在app.config.ts的providers中加入provideHttpClient(...)export const appConfig: ApplicationConfig { providers: [provideHttpClient(/* add features here, such as withInterceptors(...) */)], };由于httpResource底层走HttpClient你在provideHttpClient里配置的拦截器对其同样生效。定义响应式数据请求最简单的形式是返回一个 url 的函数把响应式依赖放进参数里userId input.requiredstring(); user httpResource(() /api/user/${userId()}); // A reactive function as argument这里有两个和HttpClient直接使用时不同的关键点响应式触发httpResource是响应式的凡是它依赖的 signal如userId变化资源都会发出一个新的 HTTP 请求立即发起请求httpResource发起请求是 eager 的资源创建时即开始请求而HttpClient只在订阅返回的Observable时才发起请求。过期请求是如何被取消的官方指南的原文行为说明是每当依赖的 signal 变化资源会发出新的 HTTP 请求如果此时已有请求处于 pending 状态资源会先取消未完成的请求再发出新请求If a request is already pending, the resource cancels the outstanding request before issuing a new one。从实现上可以核对这一机制在 resource.ts 中HttpClient的订阅被包装在资源的执行函数内并为每次请求注册了一个abortSignal监听器——当信号触发中止时onAbort会调用sub?.unsubscribe()取消该次请求的订阅。也就是说依赖变化导致的旧请求会被资源系统整体放弃不会继续把结果写回避免了过期响应覆盖新数据的情况。在模板中展示请求状态httpResource返回的资源上带有状态 signal可以直接用于模板控制分支以下示例来自官方指南if (user.hasValue()) { user-details [user]user.value() / } else if (user.error()) { divCould not load user information/div } else if (user.isLoading()) { divLoading user info.../div }指南特别指出在一个处于 error 状态的 resource 上读取valuesignal 会在运行时抛错因此建议用hasValue()守护value的读取。上面的if (user.hasValue())分支写法即遵循此建议。进阶请求对象与自定义响应类型需要传 header、query 参数或 fetch 选项时可以传入与HttpClient请求对象相似的结构其中需要响应式的属性用 signal 组合user httpResource(() ({ url: /api/user/${userId()}, method: GET, headers: { X-Special: true, }, params: { fast: yes, }, reportProgress: true, transferCache: true, }));官方示例还演示了priority、mode、redirect、cache、credentials、referrer、integrity等更多 fetch 选项完整字段定义见 HttpResourceRequest 接口。method缺省为GETreportProgress: true时进度事件会通过资源的progresssignal 投递。默认情况下响应按 JSON 解析。需要其他返回类型时使用httpResource的子函数value()的类型随之改变httpResource.text(() ({ … })); // returns a string in value() httpResource.blob(() ({ … })); // returns a Blob object in value() httpResource.arrayBuffer(() ({ … })); // returns an ArrayBuffer in value()可选分支用 parse 校验响应如果要用 Zod、Valibot 等库校验后端响应可以通过parse选项接入parse函数的返回类型即资源value的类型。官方示例以 StarWars API 为例const starWarsPersonSchema z.object({ name: z.string(), height: z.number({coerce: true}), edited: z.string().datetime(), films: z.array(z.string()), }); export class CharacterViewer { id signal(1); swPersonResource httpResource(() https://swapi.info/api/people/${this.id()}, { parse: starWarsPersonSchema.parse, }); }校验失败时错误会被封装为资源错误进入error状态而不是让应用崩溃。验证用 HttpTestingController 测试 httpResource因为httpResource是HttpClient的包装可以用与HttpClient完全相同的测试 APITest requests。配置TestBed时加入provideHttpClientTesting()请求会打到测试后端需要自定义拦截器等特性时provideHttpClient(...)必须放在provideHttpClientTesting()之前。官方指南给出的httpResource单元测试示例其中TestBed.tick()用于触发资源 effectwhenStable()确保值已传播TestBed.configureTestingModule({ providers: [provideHttpClientTesting()], }); const id signal(0); const mockBackend TestBed.inject(HttpTestingController); const response httpResource(() /data/${id()}, {injector: TestBed.inject(Injector)}); TestBed.tick(); // Triggers the effect const firstRequest mockBackend.expectOne(/data/0); firstRequest.flush(0); // Ensures the values are propagated to the httpResource await TestBed.inject(ApplicationRef).whenStable(); expect(response.value()).toEqual(0);这个示例展示了完整的验证路径expectOne(/data/0)断言依赖当前 signal 值发出的请求确实发生flush(0)模拟后端响应最后response.value()的断言确认响应被解析并写入了资源。测试文档还建议用mockBackend.verify()断言没有发出预期之外的请求可以放进afterEach()。要模拟后端错误可用req.flush(Failed!, {status: 500, statusText: Internal Server Error})触发资源的 error 分支并断言error()状态。使用限制不要用于变更类请求官方指南明确建议POST、PUT这类 mutation 不要用httpResource直接调用底层HttpClientAPI。读取value前先用hasValue()守护error 状态下直接读value会抛运行时错误。请求对象中的 url 不应包含 query 参数query 参数通过params字段指定见 HttpResourceRequest 的字段说明。完成上述步骤后你可以在测试中通过expectOneflushexpect(response.value())这条链路确认请求按预期发出、过期请求被取消、响应正确落到 signal 上模板侧则通过hasValue()/error()/isLoading()三个分支确认页面状态机与之一致。【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表