Observables VS Subjects in RxJS

เปรียบเทียบตัวแปรชนิด Observables และชนิด Subjects ใน RxJS ว่าจุดแข็ง จุดอ่อนในการใช้งานเป็นอย่างไร

Siripra Kingchan
incubate.co.th
5 min readOct 15, 2020

--

RxJS คืออะไร?

ก่อนอื่นเรามาทำความรู้จัก reactive programming กันก่อน

จากบทความข้างต้นอธิบายไว้ว่า

Reactive programming is programming with asynchronous data streams.

คือ การเขียนโปรแกรมกับสายข้อมูล (data stream) ที่เป็นแบบ asynchronous ทำให้สามารถ observe ข้อมูลหรือ event จากนั้นก็ทำงานตามข้อมูลเหล่านั้นวนไปเรื่อย ๆ รวมถึงการเปลี่ยนแปลง data stream ที่ส่งผลต่อ stream อื่นอีกด้วย

และในบทความที่สอง ได้ยกตัวอย่าง reactive programming ที่หลายคนคุ้นเคย คือการทำ Excel หรือ Spreadsheet

กำหนดค่าให้ตัวแปร x = 2 y = 3 และให้ z = x * y
เมื่อเปลี่ยนค่า x = 10 จะได้ค่า z = 30

หากไม่ใช่ reactive programming เมื่อเปลี่ยนค่า x เป็น 10 ภายหลัง ค่า z จะยังคงเป็น 6

หลักการของ reactive programming คือจะคอยรับฟังข้อมูล และจับการเปลี่ยนแปลงทุกครั้งที่เกิดขึ้น

RxJS: Reactive Extensions For JavaScript

RxJS เป็น Library ที่ถูกพัฒนาขึ้นบนพื้นฐานของ reactive programming โดยเน้นไปจัดการกับเหตุการณ์หรือค่าที่เปลี่ยนแปลงไปใน object ที่สนใจให้อยู่ในรูปของ Observable ที่วิ่งผ่าน Operator ต่าง ๆ ที่ช่วยในการจัดการกับข้อมูล ให้สามารถเลือกรับเฉพาะข้อมูลที่สนใจได้

RxJS ได้นำเอา Observer Pattern ใน GoF Design Patterns มาใช้ โดยจะมี

  • Observable คือ ฝั่งที่คอยส่งข้อมูลออกมา (producer) ซึ่งข้อมูลอาจเป็น number, string, Promise หรือ object ที่สามารถนำมา Observe ได้
  • Observer คือ ฝั่งที่คอยรับข้อมูลที่ถูกส่งออกมานั้นเอง (consumer) ซึ่งจะ subscribe หรือติดตาม Observable นั้น

เปรียบเทียบโดย Observable เป็นดารา หรือเน็ตไอดอลที่คอยโพสต์รูปภาพ หรือข่าวสาร และมี Observer เป็นเหล่าแฟนคลับที่คอยติดตาม กดไลค์ คอมเมนต์นั่นเอง

ก่อนที่จะมาเปรียบเทียบ Observables และ Subjects มาทำความรู้จักซักกะนิด

Observables เธอคือใคร?

หาก Observable เป็นดารา หรือเน็ตไอดอลที่คอยโพสต์รูปภาพ หรือข่าวสาร และ Observer เป็นเหล่าแฟนคลับที่คอยติดตาม

เราลองมาสร้าง Observable ไอดอลสาวสวยขึ้นมา ให้เหล่าแฟนคลับได้ติดตามกัน

ต่อไปจะสร้าง Observer มาตามกดไลค์แต่ละคน ชื่อว่า BlinkAsObserver

และ Observer จะมีฟังก์ชั่น 4 ตัว คือ

  • next() ใช้ดึงค่าที่สนใจออกมา
  • error() ใช้ทำคำสั่งเมื่อเกิดการ error
  • completed() ใช้ทำคำสั่งเมื่อทำงานเสร็จสิ้น
  • Subscribe(Disposable d) ใช้เมื่อมีเหตุการณ์ subcribe เกิดขึ้น และจะส่ง Disposable object เข้ามาทาง parameter ของ function โดยเราสามารถใช้ object นี้เพื่อหยุดการทำงานของการ subscribe ครั้งนั้นๆได้

ขั้นตอนต่อไป เริ่มปฏิบัติการ โดยเอา Observer ไปส่องเหล่าไอดอล ผ่านคำสั่ง subscribe

จะได้ผลลัพธ์ดังนี้

ผลลัพธ์หลังใช้คำสั่ง subscribe ผ่าน Console

คำสั่งข้างบน จะสร้างไอจีแยกแต่ละเมมเบอร์ขึ้นมา ได้ 4 ไอจี หรือ 4 Observables

หากต้องการสร้างไอจีวงเพียง 1 ไอจี ให้เปลี่ยนจาก from เป็น of จะได้ Observable เพียงอันเดียว

ผลลัพธ์หลังสร้าง BPObservable จาก from เป็น of ผ่าน Console

โดยจะสังเกตได้ว่า หากสร้าง Observable ด้วยคำสั่ง ofจะเห็นเป็น Array ทั้งก้อน แต่หากใช้คำสั่ง fromจะเกิด Observable ตามจำนวนข้อมูลใน Array ซึ่งทำให้จัดการ Observable เป็นรายตัวได้

ข้อควรระวัง

ถ้าไอดอลที่ไม่มีคนติดตาม คุณคิดว่าเขาจะอยากอัพเดตข้อมูลข่าวสารไหม? เช่นเดียวกันกับ Observable ถ้าไม่มี Observer ไหนไป subscribe Observable ตัวดังกล่าวก็จะไม่ทำงาน เหมือนเราที่จะไม่โพสต์รูป ถ้าไม่มีคนสนใจเช่นนั่นล่ะค่า

มารู้จักกันคร่าว ๆ นะคะ หากอยากรู้จักเพิ่มเติม สนิทสนมกันอีก ก็ติดตามอ่านได้ที่บทความข้างล่างเลยค่า 💖

แล้ว Subjects ล่ะ??

Subject จะเป็นทั้ง Observable และ Subscriber ในตัวเดียวกัน ดังนั้นสามารถใช้ Subject แทน Subscriber ในการ subscribe Observable ได้ และยังใช้ในการส่งต่อ Item ที่ได้รับมาไปยัง Subscriber ตัวอื่นที่ subscribe มันอยู่ หรือแม้กระทั่งสร้าง Item ใหม่ขึ้นมาได้ เพราะเนื่องจากมันเป็น Observable ในตัวมันเองอยู่แล้ว

และยังใช้ในการส่งต่อ Item ที่ได้รับมาไปยัง Subscriber ตัวอื่นที่ subscribe มันอยู่ หรือแม้กระทั้งสร้าง Item ใหม่ขึ้นมาได้ เพราะเนื่องจากมันเป็น Observable ในตัวมันเองอยู่แล้ว

Subject เป็น Hot observable คือยังคงทำงานต่อไปได้ถึงแม้ไม่มีใคร subscribe มันอยู่ ให้เราลองนึกถึงสถานีวิทยุที่ยังคงเปิดเพลงต่อไป ถึงแม้ว่าเราจะปิดวิทยุของเราไปแล้วก็ตาม และเนื่องจากมันเป็น Hot observable ดังนั้นมันจะไม่ execute operation ใหม่ทุกครั้งที่เกิดการ subscribe นั้นหมายความว่า Subscriber ทุกตัวที่ subscribe มันอยู่จะได้รับข้อมูลชุดเดียวกัน โดยไม่มีการรันโค้ดภายใน Subject ใหม่ ซึ่งผิดกับ Cold Observable ตรงที่จะรันโค้ดภายใน Observable ใหม่ทุกครั้งที่เกิดการ subscribe ขึ้น

RxJava series — part 8 — Subject คืออะไรหนอ แล้วจะใช้มันอย่างไร

จากโค้ดด้านบนจะได้ผลลัพธ์เป็น 1 1 2 2 3 3 3 เนื่องจาก 3 ถูกเพิ่มมาหลังการส่งข้อมูล 1 2 เลยได้รับค่าแค่ 3

มาอธิบาย Subject แต่ละประเภทกันค่ะ ในที่นี้ขอแทนการ subscribe ว่า ‘ฟัง’ นะคะ โดย Subject จะมีอยู่ 4 ประเภท คือ

  1. PublicSubject หรือ Subject
http://reactivex.io/documentation/subject.html

จากรูปด้านบนลองสมมุติตัว Subject เป็นวิทยุนะคะ หากเราเข้ามาฟังตั้งแต่เริ่มรายการ เราจะได้รับข้อมูลตัวสีแดง และเขียว

แต่ถ้าหากเราเข้ามาฟังทีหลัง จากรูปคือมาฟังหลังข้อมูลสีเขียว ทำให้จะไม่ได้รับข้อมูลตัวก่อนหน้า จะได้รับเฉพาะตัวสีน้ำเงิน คือเส้นข้างล่าง

แต่คนที่เข้ามาฟังก่อนจะได้รับข้อมูลครบทั้งสีแดง เขียว น้ำเงินค่ะ ตามเส้นข้างบน

2. BehaviorSubject

http://reactivex.io/documentation/subject.html

จากรูป BehaviorSubject จะเริ่มต้นด้วยการปล่อยค่าล่าสุดที่ปล่อยออกมาจาก Source Observable ก่อนค่ะ จากนั้นจึงปล่อยค่าที่ได้หลังการ ฟัง ตัวต่อมาตามรูปแบบของ PublicSubject ซึ่ง Subject ชนิดนี้จะไม่ปล่อยค่าออกมา ถ้า Source Observable ไม่ได้ปล่อยค่า หรือไม่มีค่าเริ่มต้นของ BehaviorSubject

ยกตัวอย่าง นาย A เข้าไปฟังวิทยุหลังนาย B ซึ่งมีข้อมูลก่อนหน้าเก็บในก้อนสีชมพู ซึ่งนาย B นำมาเล่าให้นาย A ฟัง จากนั้นก็รับข้อมูลไปพร้อมกัน จนกระทั่งนาย C เข้ามาก็จะได้รับข้อมูลก่อนหน้า คือก้อนสีเขียวจากเพื่อนต่อไป

3. AsyncSubject

http://reactivex.io/documentation/subject.html

AsyncSubject คือ Subject ที่จะปล่อยข้อมูลแค่ตัวล่าสุดค่าเดียวหลังทำงานเสร็จเท่านั้น

เช่น หากเราดูรายการทำอาหาร แม้ว่าเราจะเข้ามาช่วงไหนก็รายการก็ตาม เราจะไม่เก็บรายละเอียด แต่จะเอาเฉพาะสูตรในตอนจบของรายการเท่านั้น!!

4. ReplaySubject

http://reactivex.io/documentation/subject.html

ตัวนี้ก็ตามชื่อเลยค่ะ ถึงแม้เราจะเข้ามา ฟัง ทีหลังรายการเล่น แต่เรายังสามารถย้อนไปเก็บข้อมูลไปตั้งแต่ต้นได้ด้วยการ Replay

ซึ่ง Subject ตัวนี้ จะปล่อยข้อมูลทั้งหมดตั้งแต่ต้นให้ โดยไม่สนว่าคุณจะเข้ามา ฟัง ตอนไหน

พอรู้จักกันไปคร่าวๆ แล้วนะคะ กับตัวแปรที่น่ารักของเรา ทั้ง 2 ท่าน 😉 ต่อไปเรามาเปรียบกันค่า ว่าแต่ละตัวเหมาะที่จะนำไปใช้งานแบบไหน 🐱‍👤

Observables VS Subject

ขออ้างอิงจากคุณ jaideep_johny ที่สรุปไว้ดีมากเลยค่ะ

Observables

  1. เป็น cold Observable: โค้ดจะทำงาน เมื่อมีอย่างน้อย 1 observer
  2. สร้างสำเนาข้อมูล: Observable จะสร้างสำเนาข้อมูลให้แต่ละ observer
  3. ทิศทางเดียว: Observer ไม่สามารถกำหนดค่าให้ observable ได้
  4. ถ้าต้องการใช้ข้อมูลระหว่าง components ไม่ต้องส่งค่าไปยังตัวแปรใหม่ เพราะ subscribers ตัวใหม่สามารถ subscribe จาก observable ตัวเดิม และได้รับข้อมูลตั้งแต่ต้น
  5. Unicast: observable สามารถปล่อยค่าออกมาให้ได้เท่านั้น

Subject

  1. เป็น hot Observable: โค้ดจะทำงาน หรือ ส่งข้อมูลแม้จะไม่มี observer
  2. แบ่งปันข้อมูล: ข้อมูลชุดเดียวกัน จะถูกแบ่งให้ระหว่าง observer ทุกตัว
  3. สองทิศทาง: Observer สามารถกำหนดค่าให้ observable ได้
  4. ถ้าใช้ subject แล้วพลาดข้อมูลตั้งแต่ต้น สามารถใช้ Replay Subject ได้
  5. multicast: สามารถส่งค่าให้ subscribers หลายตัวได้ และยังเป็นได้ทั้ง subscribers (ตัวรับข้อมูล) และ emitter (ตัวปล่อยข้อมูล)

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

จบไปแล้วนะคะ กับการเปรียบเทียบตัวแปรใน RxJS ทั้งสองชนิด หวังว่าบทความนี้จะเกิดประโยชน์กับทุกคน ไม่ทำให้มึนงงนะคะ 🤣 หากช่วยให้เลือกตัวแปรไปใช้ได้อย่างถูกต้อง และทำให้การเขียน Reactive programming ของท่านสมบูรณ์และสวยงามยิ่งขึ้น จะอิ่มเอมใจที่สุดเลยค่ะ 😊

REFERENCE :

--

--

Siripra Kingchan
incubate.co.th

กำลังศึกษาปริญญาโท และทำวิจัยเกี่ยวกับ AI ด้าน image processing