Sự khác biệt giữa sơ đồ phẳng và sơ đồ chuyển mạch trong RxJava là gì?


149

Các rxjava doc định nghĩa của switchmap là khá mơ hồ và nó liên kết tới các trang tương tự như flatMap. Sự khác biệt giữa hai nhà khai thác là gì?


1
Về nó liên kết đến cùng một trang như phẳng . Nó thực sự đúng. Nhưng cuộn xuống phần Thông tin cụ thể về ngôn ngữ và mở toán tử thú vị. Tôi nghĩ rằng điều này nên được thực hiện tự động từ TOC, nhưng ... Ngoài ra, bạn có thể thấy hình ảnh tương tự trong javadoc .
Ruslan Stelmachenko

Câu trả lời:


180

Theo tài liệu ( http://reactivex.io/documentation/operators/flatmap.html )

các switchMapgiống như flatMap, nhưng nó sẽ chỉ phát ra các mục từ quan sát mới cho đến khi một sự kiện mới được phát ra từ những quan sát được nguồn.

Biểu đồ đá cẩm thạch cho thấy nó tốt. Lưu ý sự khác biệt trong sơ đồ:

Trong phát xạ ban đầuswitchMap thứ hai ( cẩm thạch xanh ) không phát ra phát xạ thứ hai ( ô vuông xanh ), vì phát xạ ban đầu thứ ba ( cẩm thạch xanh ) đã bắt đầu và đã phát ra phát xạ ánh xạ thứ nhất ( kim cương xanh ). Nói cách khác, chỉ có phát thải xanh đầu tiên trong hai bản đồ xảy ra; không có hình vuông màu xanh lá cây được phát ra vì viên kim cương màu xanh đánh bại nó.

Trong flatMap, tất cả các kết quả được ánh xạ sẽ được phát ra, ngay cả khi chúng "cũ". Nói cách khác, cả hai đầu tiên thứ hai của ánh xạ thải xanh xảy ra - một hình vuông màu xanh lá cây sẽ đã phát ra (nếu họ sử dụng chức năng bản đồ phù hợp; vì họ đã làm không, bạn sẽ thấy thứ hai viên kim cương màu xanh lá cây, mặc dù nó được phát ra sau các đầu kim cương màu xanh)

chuyển đổi bản đồ trong switchMap nếu bản gốc quan sát được phát ra thứ gì đó mới, khí thải trước đó không còn tạo ra các vật quan sát được ánh xạ;  đây là một cách hiệu quả để tránh kết quả cũ

Bản đồ phẳng

trong switchMap nếu bản gốc quan sát được phát ra thứ gì đó mới, khí thải trước đó không còn tạo ra các vật quan sát được ánh xạ;  đây là một cách hiệu quả để avoi stale kết quả


4
Cảm ơn, sơ đồ là rất hữu ích. Bạn có biết một ví dụ trong thế giới thực nơi switchMap sẽ được sử dụng không?
Julian Go

1
@JulianGo có một ví dụ ở đây: github.com/samuelgruetter/rx-playground/blob/master/ mẹo Nó sử dụng .map(func).switch, nhưng nó giống như .switchMap(func).
Samuel Gruetter

2
Chỉ trong trường hợp ai đó vẫn cần một ví dụ thực tế về switchMap, anh ta có thể theo liên kết liên kết này và nó sẽ hiểu khi nào nên sử dụng swicthMap thay vì FlatMap.
hermannovich

2
Để biết ví dụ sử dụng SwitchMap từ Ben Lesh bằng RxJs5 - xem phút 25-26 tại đây - youtube.com/watch?v=3LKMwkuK0ZE đối với tôi, bản đồ phẳng đã được hiểu ...
arcseldon

7
Biểu đồ đá cẩm thạch cho thấy nó tốt? Gì? Tôi đoán nếu bạn đã hiểu sơ đồ chuyển mạch có thể.
Helzgate

166

Tôi đã bắt gặp điều này khi thực hiện "tìm kiếm tức thời" - tức là khi người dùng nhập vào hộp văn bản và kết quả xuất hiện gần thời gian thực với mỗi hành trình phím. Giải pháp có vẻ là:

  1. Có một chủ đề, chẳng hạn như PublishSubject of String
  2. Trong hộp văn bản thay đổi cuộc gọi lại, gọi .onNext (văn bản)
  3. áp dụng bộ lọc .debounce để đánh giá các truy vấn máy chủ giới hạn
  4. áp dụng .switchMap để thực hiện truy vấn máy chủ - lấy cụm từ tìm kiếm và trả về Có thể quan sát được của SearchResponse
  5. áp dụng .subscribe với một phương thức tiêu thụ SearchResponse và cập nhật giao diện người dùng.

Với FlatMap, các kết quả tìm kiếm có thể cũ, vì các phản hồi tìm kiếm có thể trở lại không theo thứ tự. Để khắc phục điều này, switchMap nên được sử dụng, vì nó đảm bảo rằng một quan sát cũ sẽ bị hủy đăng ký một khi một cái mới hơn được cung cấp.

Vì vậy, tóm lại, FlatMap nên được sử dụng khi tất cả các kết quả quan trọng, bất kể thời gian của chúng và switchMap nên được sử dụng khi chỉ kết quả từ vấn đề quan sát cuối cùng.


Bạn có thể kiểm tra ví dụ này trong GitHub
Cabezas

95

Không có cuộc thảo luận FlatMap nào hoàn tất mà không so sánh và đối chiếu với switchMap, concatMapconcatMapEager.

Tất cả các phương thức này đều thực hiện Func1chuyển đổi luồng thành Observables sau đó được phát ra; sự khác biệt là khi các trả về Observableđược đăng ký và hủy đăng ký, và nếu và khi những phát thải của những đó Observableđược phát ra bởi ____Mapnhà điều hành trong câu hỏi.

  • flatMapđăng ký càng nhiều Observables phát ra càng tốt. (Đây là số phụ thuộc nền tảng. Ví dụ: số thấp hơn trên Android) Sử dụng số này khi đơn hàng KHÔNG quan trọng và bạn muốn phát thải càng sớm càng tốt.
  • concatMapđăng ký đầu tiên Observablevà chỉ đăng ký tiếp theo Observablekhi hoàn thành trước đó. Sử dụng điều này khi trật tự là quan trọng và bạn muốn bảo tồn tài nguyên. Một ví dụ hoàn hảo là hoãn cuộc gọi mạng bằng cách kiểm tra bộ đệm trước. Điều đó thường có thể được theo sau bởi một .first()hoặc .takeFirst()để tránh làm những công việc không cần thiết.

    http://blog.danlew.net/2015/06/22/loading-data-from-mult Môn-source-with-rxjava /

  • concatMapEagerhoạt động giống nhau nhưng đăng ký càng nhiều càng tốt (phụ thuộc vào nền tảng) nhưng sẽ chỉ phát ra sau khi Observablehoàn thành trước đó . Hoàn hảo khi bạn có rất nhiều xử lý song song cần phải được thực hiện, nhưng (không giống như FlatMap) bạn muốn duy trì thứ tự ban đầu.

  • switchMapsẽ đăng ký lần cuối Observablemà nó gặp và hủy đăng ký từ tất cả các lần trước Observable. Điều này hoàn hảo cho các trường hợp như đề xuất tìm kiếm: một khi người dùng đã thay đổi truy vấn tìm kiếm của họ, yêu cầu cũ không còn được quan tâm nữa, vì vậy nó không được đăng ký và điểm cuối Api hoạt động tốt sẽ hủy yêu cầu mạng.

Nếu bạn đang trả về Observablekhông phải subscribeOnmột chủ đề khác, tất cả các phương thức trên có thể hoạt động giống nhau. Hành vi thú vị và hữu ích xuất hiện khi bạn cho phép các Observables lồng nhau hành động theo chủ đề riêng của chúng. Sau đó, bạn có thể nhận được nhiều lợi ích từ xử lý song song, và thông minh hủy đăng ký hoặc không đăng ký từ Observables mà không quan tâm bạn Subscribers

  • ambcũng có thể được quan tâm. Cho bất kỳ số lượng nào Observable, nó phát ra cùng một vật phẩm mà người đầu tiên Observablephát ra bất cứ thứ gì phát ra. Điều đó có thể hữu ích khi bạn có nhiều nguồn có thể / nên trả lại cùng một thứ và bạn muốn hiệu suất. ví dụ: sắp xếp, bạn có thể ambsắp xếp nhanh với sắp xếp hợp nhất và sử dụng cái nào nhanh hơn.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- mọi lời giải thích của switchMap vs flatMaptôi gặp phải trước đây, đã bỏ qua khía cạnh quan trọng này, bây giờ mọi thứ đã rõ ràng hơn. Cảm ơn bạn.
Andy Res

55

switchMap đã từng được gọi là FlatMapLatest trong RxJS 4.

Về cơ bản, nó chỉ truyền vào các sự kiện từ những người quan sát mới nhất và hủy đăng ký từ sự kiện trước đó.


@EpicPandaForce Mặc dù không phù hợp với kết hợp, nó phát ra các giá trị mới nhất bất cứ khi nào một nguồn có thể quan sát được phát ra (không phát ra một lần).
Michael Fry

2
Một phần lý do nó được gọi là switchMap là vì bạn có thể tự thực hiện toán tử này bằng cách sử dụng o.map (...). Switch (). Mặc dù sau đó tôi sẽ tưởng tượng đó là mapSwitch, thứ dường như không dễ dàng tặc lưỡi.
Niall Connaughton

7

Map, FlatMap, ConcatMapSwitchMap áp dụng một chức năng hoặc sửa đổi dữ liệu được phát ra bởi một Đài quan sát.

  • Bản đồ sửa đổi từng mục được phát ra từ một nguồn Có thể quan sát được và phát ra mục được sửa đổi.

  • FlatMap, SwitchMapConcatMap cũng áp dụng một chức năng trên mỗi mục được phát ra nhưng thay vì trả về mục đã sửa đổi, nó sẽ trả về bản thân Observable có thể phát lại dữ liệu.

  • Công việc FlatMapConcatMap khá giống nhau. Họ hợp nhất các mục được phát ra từ nhiều Đài quan sát và trả về một Quan sát duy nhất.

  • Sự khác biệt giữa FlatMapConcatMap là thứ tự mà các mục được phát ra.
  • FlatMap có thể xen kẽ các mục trong khi phát ra, tức là thứ tự các mục được phát ra không được duy trì.
  • ConcatMap bảo tồn thứ tự của các mặt hàng. Nhưng nhược điểm chính của ConcatMap là, nó phải chờ mỗi Observable hoàn thành công việc của nó do đó không đồng bộ không được duy trì.
  • SwitchMap khác một chút so với FlatMapConcatMap . SwitchMap hủy đăng ký từ nguồn trước Có thể quan sát được mỗi khi mục mới bắt đầu phát ra, do đó luôn phát ra các mục từ Hiện tại có thể quan sát được.

1

Nếu bạn đang tìm kiếm một mã ví dụ

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

Bạn có thể xem thêm ví dụ tại đây https://github.com/politrons/reactive


4
Nhưng bạn bỏ lỡ tính năng chính của switchMap để phân biệt nó với FlatMap - chỉ những vấn đề quan sát gần đây nhất, trong khi hủy đăng ký từ những cái trước đó.
Artem Novikov

3
Trong ví dụ này, khi bạn thay thế switchMapbằng flatMapnó sẽ hoạt động chính xác như nhau.
Piotr Wittchen

1

Đây là một ví dụ dài hơn 101 dòng . Điều đó giải thích điều cho tôi.

Giống như đã nói: nó nhận được cái cuối cùng có thể quan sát được (cái chậm nhất nếu bạn muốn) và bỏ qua phần còn lại.

Kết quả là:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

Bạn thấy A bị bỏ qua.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.