Observables VS Subjects in RxJS
เปรียบเทียบตัวแปรชนิด Observables และชนิด Subjects ใน RxJS ว่าจุดแข็ง จุดอ่อนในการใช้งานเป็นอย่างไร
RxJS คืออะไร?
ก่อนอื่นเรามาทำความรู้จัก reactive programming กันก่อน
จากบทความข้างต้นอธิบายไว้ว่า
Reactive programming is programming with asynchronous data streams.
คือ การเขียนโปรแกรมกับสายข้อมูล (data stream) ที่เป็นแบบ asynchronous ทำให้สามารถ observe ข้อมูลหรือ event จากนั้นก็ทำงานตามข้อมูลเหล่านั้นวนไปเรื่อย ๆ รวมถึงการเปลี่ยนแปลง data stream ที่ส่งผลต่อ stream อื่นอีกด้วย
และในบทความที่สอง ได้ยกตัวอย่าง reactive programming ที่หลายคนคุ้นเคย คือการทำ Excel หรือ Spreadsheet
หากไม่ใช่ reactive programming เมื่อเปลี่ยนค่า x เป็น 10 ภายหลัง ค่า z จะยังคงเป็น 6
var x = 2
var y = 3
var z = x * y // z is 6
x = 10
// z is still 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 ไอดอลสาวสวยขึ้นมา ให้เหล่าแฟนคลับได้ติดตามกัน
import { of, from } from ‘rxjs’;// create new observable, from arrayconst BlackPinkObservable = from([‘lisa’,‘jennie’,‘rose’,‘jisoo’])
ต่อไปจะสร้าง Observer มาตามกดไลค์แต่ละคน ชื่อว่า BlinkAsObserver
const BlinkAsObserver = {next: (idol) => {console.log(`I like ${idol}`)},error: (err) => {console.log(`I’m sorry~`)},complete: () =>{console.log(`I like all member`)},}
และ Observer จะมีฟังก์ชั่น 4 ตัว คือ
next()
ใช้ดึงค่าที่สนใจออกมาerror()
ใช้ทำคำสั่งเมื่อเกิดการ errorcompleted()
ใช้ทำคำสั่งเมื่อทำงานเสร็จสิ้นSubscribe(Disposable d)
ใช้เมื่อมีเหตุการณ์subcribe
เกิดขึ้น และจะส่งDisposable
object เข้ามาทาง parameter ของ function โดยเราสามารถใช้ object นี้เพื่อหยุดการทำงานของการsubscribe
ครั้งนั้นๆได้
ขั้นตอนต่อไป เริ่มปฏิบัติการ โดยเอา Observer ไปส่องเหล่าไอดอล ผ่านคำสั่ง subscribe
BPObservable.subscribe(BlinkAsObserver)
จะได้ผลลัพธ์ดังนี้
คำสั่งข้างบน จะสร้างไอจีแยกแต่ละเมมเบอร์ขึ้นมา ได้ 4 ไอจี หรือ 4 Observables
หากต้องการสร้างไอจีวงเพียง 1 ไอจี ให้เปลี่ยนจาก from
เป็น of
จะได้ Observable เพียงอันเดียว
const BPObservable = of([‘lisa’,‘jennie’,‘rose’,‘jisoo’])
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 ประเภท คือ
- PublicSubject หรือ Subject
จากรูปด้านบนลองสมมุติตัว Subject เป็นวิทยุนะคะ หากเราเข้ามาฟังตั้งแต่เริ่มรายการ เราจะได้รับข้อมูลตัวสีแดง และเขียว
แต่ถ้าหากเราเข้ามาฟังทีหลัง จากรูปคือมาฟังหลังข้อมูลสีเขียว ทำให้จะไม่ได้รับข้อมูลตัวก่อนหน้า จะได้รับเฉพาะตัวสีน้ำเงิน คือเส้นข้างล่าง
แต่คนที่เข้ามาฟังก่อนจะได้รับข้อมูลครบทั้งสีแดง เขียว น้ำเงินค่ะ ตามเส้นข้างบน
2. BehaviorSubject
จากรูป BehaviorSubject จะเริ่มต้นด้วยการปล่อยค่าล่าสุดที่ปล่อยออกมาจาก Source Observable ก่อนค่ะ จากนั้นจึงปล่อยค่าที่ได้หลังการ ฟัง ตัวต่อมาตามรูปแบบของ PublicSubject ซึ่ง Subject ชนิดนี้จะไม่ปล่อยค่าออกมา ถ้า Source Observable ไม่ได้ปล่อยค่า หรือไม่มีค่าเริ่มต้นของ BehaviorSubject
ยกตัวอย่าง นาย A เข้าไปฟังวิทยุหลังนาย B ซึ่งมีข้อมูลก่อนหน้าเก็บในก้อนสีชมพู ซึ่งนาย B นำมาเล่าให้นาย A ฟัง จากนั้นก็รับข้อมูลไปพร้อมกัน จนกระทั่งนาย C เข้ามาก็จะได้รับข้อมูลก่อนหน้า คือก้อนสีเขียวจากเพื่อนต่อไป
3. AsyncSubject
AsyncSubject คือ Subject ที่จะปล่อยข้อมูลแค่ตัวล่าสุดค่าเดียวหลังทำงานเสร็จเท่านั้น
เช่น หากเราดูรายการทำอาหาร แม้ว่าเราจะเข้ามาช่วงไหนก็รายการก็ตาม เราจะไม่เก็บรายละเอียด แต่จะเอาเฉพาะสูตรในตอนจบของรายการเท่านั้น!!
4. ReplaySubject
ตัวนี้ก็ตามชื่อเลยค่ะ ถึงแม้เราจะเข้ามา ฟัง ทีหลังรายการเล่น แต่เรายังสามารถย้อนไปเก็บข้อมูลไปตั้งแต่ต้นได้ด้วยการ Replay
ซึ่ง Subject ตัวนี้ จะปล่อยข้อมูลทั้งหมดตั้งแต่ต้นให้ โดยไม่สนว่าคุณจะเข้ามา ฟัง ตอนไหน
พอรู้จักกันไปคร่าวๆ แล้วนะคะ กับตัวแปรที่น่ารักของเรา ทั้ง 2 ท่าน 😉 ต่อไปเรามาเปรียบกันค่า ว่าแต่ละตัวเหมาะที่จะนำไปใช้งานแบบไหน 🐱👤
Observables VS Subject
ขออ้างอิงจากคุณ jaideep_johny ที่สรุปไว้ดีมากเลยค่ะ
Observables
- เป็น cold Observable: โค้ดจะทำงาน เมื่อมีอย่างน้อย 1 observer
- สร้างสำเนาข้อมูล: Observable จะสร้างสำเนาข้อมูลให้แต่ละ observer
- ทิศทางเดียว: Observer ไม่สามารถกำหนดค่าให้ observable ได้
- ถ้าต้องการใช้ข้อมูลระหว่าง components ไม่ต้องส่งค่าไปยังตัวแปรใหม่ เพราะ subscribers ตัวใหม่สามารถ subscribe จาก observable ตัวเดิม และได้รับข้อมูลตั้งแต่ต้น
- Unicast: observable สามารถปล่อยค่าออกมาให้ได้เท่านั้น
Subject
- เป็น hot Observable: โค้ดจะทำงาน หรือ ส่งข้อมูลแม้จะไม่มี observer
- แบ่งปันข้อมูล: ข้อมูลชุดเดียวกัน จะถูกแบ่งให้ระหว่าง observer ทุกตัว
- สองทิศทาง: Observer สามารถกำหนดค่าให้ observable ได้
- ถ้าใช้ subject แล้วพลาดข้อมูลตั้งแต่ต้น สามารถใช้ Replay Subject ได้
- multicast: สามารถส่งค่าให้ subscribers หลายตัวได้ และยังเป็นได้ทั้ง subscribers (ตัวรับข้อมูล) และ emitter (ตัวปล่อยข้อมูล)
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
จบไปแล้วนะคะ กับการเปรียบเทียบตัวแปรใน RxJS ทั้งสองชนิด หวังว่าบทความนี้จะเกิดประโยชน์กับทุกคน ไม่ทำให้มึนงงนะคะ 🤣 หากช่วยให้เลือกตัวแปรไปใช้ได้อย่างถูกต้อง และทำให้การเขียน Reactive programming ของท่านสมบูรณ์และสวยงามยิ่งขึ้น จะอิ่มเอมใจที่สุดเลยค่ะ 😊
REFERENCE :