Angular中Observable常见问题与解决方法
在Angular中,Observable是处理异步操作的核心工具,支持取消订阅、多次发射数据,并通过pipe操作符实现过滤、映射等变换。与Promise相比,其状态可多次改变。单元测试中,通过构造mock数据能测试嵌套Observable的数据流,常用于HTTP请求与事件流。
Angular Observable 完全指南:核心用法与实战技巧
熟悉 Promise 的朋友可能会觉得 Observable 非常相似——两者确实都能处理异步操作。不过 Observable 在功能上更为强大且灵活。下面我们系统梳理一下 Observable 的典型用法与关键特性。
使用之前,先要在对应组件的文件顶部引入相应模块:
import { Observable } from 'rxjs';
假设我们要创建一个发送异步请求的服务文件 storage.service.ts,把它放在 service 层中,任何需要的地方都可以直接注入使用。
Observable 的基本用法与 Promise 类似:先 new 一个实例,实例接收一个函数参数,函数内部实现异步操作;该函数还接收一个 observer 参数,通过 observer.next 将异步数据推送出来,外部通过订阅即可接收。
// observable 使用之前先引入
getObservable(){
return new Observable((observer)=>{
setTimeout(()=>{
var data = 'observer数据'
observer.next(data) //相当于promise的resolve
},2000)
})
}
然后在 home 组件中调用这个服务。注意:需要先在 home.ts 中引入 storage.service.ts,并在 constructor 里声明注入变量:
import { StorageService } from 'src/app/services/storage.service';
constructor(public storage:StorageService) { }
之后便可在 home 组件中订阅 observer.next 抛出的数据:
let oberverData = this.storage.getObservable()
let d = oberverData.subscribe((res)=>{ //相当于promise的then
console.log(res)
})
然而 Observable 相比 Promise 还提供了几个关键增强能力,下面逐一解析。
1、取消订阅:随时终止数据流
Observable 允许在订阅之后随时手动取消订阅,避免不必要的资源占用或内存泄露。
setTimeout(()=>{
d.unsubscribe() //一秒钟之后取消订阅,接收不到消息
},1000)
2、多次输出:支持持续推送数据
Promise 的状态一旦从 pending 变为 reject 或 resolve 后就不可再变更,因此无法多次输出同一个 resolve 的值。但 Observable 天然支持多次异步推送。请看对比示例:
let p = new Promise(resolve=>{
setInterval(()=>{
resolve('promise interval值')
},2000)
})
p.then(res=>console.log(res)) //只输出一次
// observable
let o = new Observable(observer=>{
setInterval(()=>{
observer.next('observable interval值')
},2000)
})
o.subscribe(res=>console.log(res)) //每隔2秒输出一次
3、使用 pipe 对数据进行变换与过滤
通过 RxJS 的 pipe 操作符,可以对发射的数据进行过滤、映射、组合等复杂处理,实现响应式数据流操作。
let o1 = this.storage.getObservable1()
o1.pipe(
filter((data:any)=> {
return data%2 == 0
}),
map(value => {
return value*value
})
).subscribe(res=>console.log(res))
Angular Observable 数据类型的单元测试 mock 数据准备
假设有一个组件,它的 items 属性是一个嵌套的 Observable:

items$: Observable[]> = this.componentData$.pipe( map((data) => data.productCodes.trim().split(' ')), map((codes) => codes.map((code) => this.productService.get(code, this.PRODUCT_SCOPE)) ) );
ComponentData$ 的类型定义:
private componentData$: Observable= this.componentData.data$.pipe( filter(Boolean) );
Model 接口的定义:

componentData$ 的类型为 Observable,在 map 的回调中又嵌套了另一个 map 操作,因此最终返回的类型是嵌套的 Observable。

由于 items$ 的数据来自 componentData$,而 componentData$ 又源自 componentData,所以只需要构造好 componentData 的模拟数据即可:
private componentData$: Observable= this.componentData.data$.pipe( filter(Boolean) );
下面展示如何在单元测试中创建 mock 数据,示例为 MockCmsProductCarouselComponent:

完整解决方案
const mockComponentData: CmsProductCarouselComponent = {
uid: '001',
typeCode: 'ProductCarouselComponent',
modifiedTime: new Date('2017-12-21T18:15:15+0000'),
popup: 'false',
productCodes: productCodeArray.join(' '),
scroll: 'ALLVISIBLE',
title: 'Mock Title',
name: 'Mock Product Carousel',
container: 'false',
};
const MockCmsProductCarouselComponent = >{
data$: of(mockComponentData),
};
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
如何用拖放在Flask看板应用中更新数据库状态
在Flask看板应用中,通过HTML5拖放API结合前端fetch异步POST请求,将拖拽任务的task_id和target_state发送至后端路由;后端接收JSON后更新数据库并提交事务,实现跨列拖拽时实时更新状态。需注意将事件绑定到容器而非子元素,并在ondragover中阻止默认行为以确保drop触发。
如何用CSS :has()选择器快速实现悬停span显示相邻div
利用CSS的:has()伪类选择器,通过` bar:has(> baz:hover)+ qux`实现悬停内联元素时显示相邻块级容器,解决了传统相邻兄弟选择器无法跨层级匹配的局限,可用于悬停图标显示详情框等交互场景。需注意浏览器兼容性和性能优化,避免过度使用影响渲染效率。
display:block居中段落文本的响应式实现方法
通过`display:block`与`max-width`限制宽度,配合`margin:auto`使段落块水平居中并实现响应式布局;同时用CSS统一控制段落间距,避免脱离文档流,提升可读性与维护性。
JavaScript代码去重:高效避免重复编写的技巧
将重复代码中的变化点提取为参数,利用ES6模板字符串动态生成选择器,可消除重复、保持一致性。注意参数安全性,必要时进行白名单校验;批量化场景可扩展为数组形式;现代框架中更推荐数据驱动或组件化封装替代手动选择器。
使用容器查询单位cqw实现表单输入框相对于祖父容器百分比宽度
利用CSS容器查询单位cqw,表单输入框宽度可直接基于祖父容器计算,绕过中间包装器尺寸干扰,实现简洁响应式布局,无需硬编码或JavaScript,显著降低维护成本,提升嵌套结构下的布局灵活性。
- 热门数据榜
相关攻略
2026-07-09 07:01
2026-07-09 07:01
2026-07-09 07:01
2026-07-09 07:00
2026-07-09 07:00
2026-07-09 07:00
2026-07-09 07:00
2026-07-09 07:00
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

