前端阅读 05月27日 21:47
RxJS 中 switchMap、mergeMap、concatMap 有什么区别?常用操作符有哪些?
答案:六类核心操作符面试中最常考的 RxJS 操作符分六类:创建类:of、from、interval、timer — 把同步值、数组、Promise、定时器转为 Observable。转换类:map 逐值转换;switchMap 切换到新 Observable 并取消前一个(搜索框场景首选);mergeMap 并行处理所有内部 Observable(不取消,不保证顺序);concatMap 顺序处理,上一个完成才订阅下一个。过滤类:filter 条件过滤;take(n) 只取前 n 个;takeUntil(notifier) notifier 发出时终止;debounceTime 停顿后才发出(防抖);throttleTime 间隔内只取第一个(节流)。组合类:merge 并行合并;concat 顺序连接;combineLatest 任一更新都组合最新值;zip 按索引一一配对。错误处理类:catchError 捕获并返回替代 Observable;retry(n) 失败后自动重试 n 次。工具类:tap 执行副作用不改值(调试利器);delay 延迟发射;distinctUntilChanged 连续重复值只发一次。switchMap vs mergeMap vs concatMap:面试最高频对比三者的核心区别在于对前一个内部 Observable 的处理策略:switchMap:新值到来 → 取消上一个 → 订阅新的。搜索框、路由切换等竞态场景必选,保证只拿到最新结果。mergeMap:全部并行订阅,互不干扰。适合批量请求、日志上报等不关心顺序的场景。可传第二参数控制并发数。concatMap:排队串行,上一个完成才订阅下一个。适合顺序敏感的写操作,如依次保存表单步骤。// switchMap:搜索框 — 自动取消旧请求,避免竞态fromEvent(input, 'input').pipe( debounceTime(300), switchMap(query => http.get('/search', { query })))// mergeMap:批量删除 — 限制3并发ids.pipe(mergeMap(id => http.delete(`/item/${id}`), 3))// concatMap:串行保存 — 保证顺序actions.pipe(concatMap(action => http.post('/save', action)))选错操作符的后果:搜索场景用 mergeMap 会显示旧请求结果覆盖新结果;表单保存用 mergeMap 可能后发先至导致数据错乱。高频实战组合模式// 搜索防抖 + 去重 + 空值过滤 + 自动取消旧请求searchInput.pipe( debounceTime(300), distinctUntilChanged(), switchMap(query => query.length > 0 ? searchAPI(query) : EMPTY))// 表单自动保存(去重 + 防抖)form.valueChanges.pipe( debounceTime(1000), distinctUntilChanged(), switchMap(data => saveAPI(data)))追问方向combineLatest vs zip 的区别?— combineLatest 任一更新即触发输出,zip 等所有 Observable 都发了新值才按索引配对如何避免内存泄漏?— takeUntil(destroy$\) 模式,组件销毁时 destroy$.next() 统一取消,优于手动 unsubscribeshareReplay(1) 解决什么问题?— 多订阅者共享同一数据源并缓存最新值,避免重复 HTTP 请求exhaustMap 是什么?— 忽略新值直到当前内部 Observable 完成,适合防止重复提交(登录按钮连击)forkJoin vs combineLatest?— forkJoin 等所有完成后只取各自最后一个值,类似 Promise.all;combineLatest 每次变化都触发