Praneat Blog

Wongsathorn Phaisarnrungpana
Game Developer
20 Apr 2020

มาใช้ Reactive Extensions for Unity (UniRx) กันเถอะ !!! Part3

สารพัด Operator Do

DoOnSubscribe

เจ้า Operator DoOnSubscribe นี้ เมื่อถูกเรียกใช้แล้วจะทำงานทันทีเมื่อมีการสั่ง Subscribe เกิดขึ้น โดยไม่สนว่าสิ่งที่เราทำการ Subscribe นั้นจะทำงานเสร็จแล้วหรือยังและยังทำงานโดยไม่สนใจอีกว่าสิ่งที่เรา Subscribe ไป หรือ Request ที่เรายิงไปนั้นจะ Error หรือสำเร็จหรือไม่อีกด้วย ตัวอย่างเช่น

Ex.1

string url = "https://www.google.co.th/";
ObservableWWW.Get(url)
             .DoOnSubscribe(() => Debug.Log("DoOnSubscribe Operator"))
             .Subscribe((obj) => Debug.Log("Subscribe"));

จาก Code ด้านบน ผลลัพธ์ที่ได้นั้นเราจะเห็นคำว่า DoOnSubscribe นั้นถูกโชว์ขึ้นมาก่อน แล้วอีกสักพักเมื่อมี Repond ตอบกลับมาถึงจะโชว์คำว่า Subscribe ตามมา

Ex.2

string url = "http://wwww.something.co.th/";
ObservableWWW.Get(url)
             .DoOnSubscribe(() => Debug.Log("DoOnSubscribe Operator"))
             .Subscribe((obj) => Debug.Log("Subscribe Operator"));

จาก Code ด้านบน หากเราทดสอบยิง Request ไปที่ url ที่ไม่มีอยู่จริงแทนที่การยิงไปที่ google โดยผลลัพธ์ที่ได้นั้น ใน Console เราจะยังเห็นคำว่า DoOnSubscribe อยู่พร้อมกับ Error ที่เกืดขึ้น แต่จะไม่เห็นคำว่า Subscribe อยู่ใน Console

Ex.3

string url = "http://www.something.co.th/";
ObservableWWW.Get(url)
             .CatchIgnore((Exception ex) => Debug.Log("CatchIgnore"))
             .DoOnSubscribe(() => Debug.Log("DoOnSubscribe Operator"))
             .Subscribe((obj) => Debug.Log("Subscribe Operator"));

ผลลัพธ์ที่ได้จาก Code เมื่อมีการใช้ CatchIgnore ในการ Handler Error ที่เกิดจากการยิง Request ไปหา Url ที่ไม่มีอยู่จริง

Do

การทำงานของ Operator Do จะทำงานก่อน Operator Subscribe และ จะทำงานก็ต่อเมื่อ Observable ที่เรา Subscribe ไปนั้นทำงานเสร็จและไม่มี Error ใดๆเกืดขึ้น โดยใน Operator Do จะรับ Action โดย Type จะขึ้นอยู่กับ Respond หรือสิ่งที่ได้หรือผลลัพธ์ของ Observable นั้นๆเช่น

Observable.Create() หรือ ObservableWWW.Get(url) Operator Do ก็จะรับ Parameter เป็น Action

Observable.Create() Operator Do ก็จะรับ Parameter เป็น Action

Ex.1

string url = "https://www.google.co.th/";
ObservableWWW.Get(url)
             .Do((obj) => Debug.Log("Do Operator"))
             .Subscribe((obj) => Debug.Log("Subscribe Operator"));

ในรูปตัวอย่างเราจะเห็นว่า Operator Do นั้นจะทำงานก่อนที่ Subscribe จะทำงาน

Ex.2

string errUrl = "http://www.something.co.th";
ObservableWWW.Get(errUrl)
                     .Do((obj) => Debug.Log("Do Operator"))
                     .CatchIgnore((Exception ex) => Debug.Log("CatchIgnore"))
                     .Subscribe((obj) => Debug.Log("Subscribe"));

ผลลัพธ์ที่ได้จาก Code ด้านบน โดยเราจะเห็นว่า Operator Catchignore จะทำงานแทน Operator Do หาก Request ที่เรายิงไปนั้นเกิดการข้อผิดพลาดหรือ Error

DoOnComplete

เจ้า Operator DoOnComplete จะทำงานก็ต่อเมื่อ Operator Subscribe ทำงานเสร็จและ ไม่มี Error ใดๆเกิดขึ้น ไม่ว่าจะเป็น Error ที่เกิดจาก Observable หรือ Error ที่เกิดจาก Subscribe ก็ตาม

Ex.1

string url = "https://www.google.co.th/";
ObservableWWW.Get(url)
             .DoOnCompleted(() => Debug.Log("DoOnCompleted"))
             .Subscribe((obj) => Debug.Log("Subcribe"));

ผลลัพธ์ที่ได้จาก Code ด้านบน จะเห็นว่า Operator DoOnComplete จะทำงานหลังจากที่ Subscribe ทำงานเสร็จเรียบร้อยไปแล้ว

Ex.2

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";

ObservableWWW.Get(errorUrl)
             .DoOnCompleted(() => Debug.Log("DoOnCompleted"))
             .Subscribe((obj) => Debug.Log("Subcribe"));

ผลลัพธ์ที่ได้จาก Code ด้านบนจะเห็นว่า Operator DoOnComplete จะไม่ทำงานหาก Request ที่เรายิงไปนั้นเกิด Error ขึ้น

Ex.3

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";

ObservableWWW.Get(errorUrl)
             .DoOnCompleted(() => Debug.Log("DoOnCompleted"))
             .CatchIgnore((Exception ex) => Debug.Log("CatchIgnore"))
             .Subscribe((obj) => Debug.Log("Subscribe"));

Ex.4

string url = "https://www.google.co.th/";
ObservableWWW.Get(url)
             .DoOnCompleted(() => Debug.Log("DoOnCompleted"))
              .Subscribe((obj) =>
              {
                    Debug.Log("Subscribe");
                    GameObject go = null;
                    Debug.Log("GameObject Name : " + go.name);
              });

จาก Code ด้านบน ผลลัพธ์ที่เกิดขึ้นใน Console จะเห็นว่า หากใน Subscribe เกิด Error ขึ้น เจ้า Operator DoOnComplete ก็จะไม่ทำงาน พร้อมกับ throw errror ออกมาที่ console

DoOnTerminate

Operator DoOnTerminate จะเป็น Operator ท้ายสุดที่ทำงานหลังจากที่มีการ Subscribe ไปแล้ว และจะทำงานเสมอ ไม่ว่าสิ่งที่เรา Subscribe หรือ สิ่งที่เราทำใน Subscribe จะเกิดข้อผิดพลาดหรือ Error ขึ้นหรือไม่

Ex.1

string url = "https://www.google.co.th/";
ObservableWWW.Get(url)
             .DoOnTerminate(() => Debug.Log("DoOnTerminate"))
             .Subscribe((obj) => Debug.Log("Subscribe"));

ผลการทำงานของ Code ด้านบน โดยจะเห็นว่า Operator DoOnTerminate จะทำงานหลังจากที่ Subscribe เสร็จแล้ว

Ex.2

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";
ObservableWWW.Get(errorUrl)
             .DoOnTerminate(() => Debug.Log("DoOnTerminate"))
             .Subscribe((obj) => Debug.Log("Subscribe"));

Operator DoOnTerminate จะยังทำงาน แม้สิ่งที่เราทำการ Subscribe หรือ Request ที่เรายิงไปจะเกิดข้อผิดพลาดหรือ Error ขึ้น

Ex.3

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";
ObservableWWW.Get(errorUrl)
             .CatchIgnore((Exception obj) => Debug.Log("CatchIgnore"))
             .DoOnTerminate(() => Debug.Log("DoOnTerminate"))
             .Subscribe((obj) => Debug.Log("Subscribe"));

Operator DoOnTerminate จะยังทำงานถึงแม้จะมีการเรียกใช้ Operator CatchIgnore เพื่อ Handler Error ที่เกิดขึ้นก็ตาม

DoOnCancel()

DoOnCancel จะเป็น Operator ที่ทำงานหลังจากที่มีการยกเลิกการทำงานของ Observable นั้นๆ โดยการสั่ง Dispose

Ex.1

string url = "https://www.google.co.th/";

IDisposable disposable = ObservableWWW.Get(url)
            .DoOnCancel(() =>
            {
               Debug.Log("DoOnCancel");
            }).Subscribe((obj) => Debug.Log("Subscribe"));

disposable.Dispose();

DoOnError()

การทำงานของ Operator DoOnError จะคล้ายๆกับการทำงานของ CatchIgnore โดยจะทำงานเมื่อสิ่งที่เราทำการ Subscribe หรือ Observable นั้นเกิด Error หรือข้อผิดพลาดขึ้น แต่จะยังคง throw exception ออกมาที่หน้า console และไม่ทำงานคำสั่งต่างใน Subscribe ต่างกับ CatchIgnore ที่จะไม่ throw exception นั้นๆออกมาที่หน้า console

Ex.1

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";

ObservableWWW.Get(errorUrl)
             .DoOnError((Exception ex) =>
             {
                Debug.Log("DoOnError");
             }).Subscribe((obj) => Debug.Log("Subscribe"));

Operator DoOnSubscribe ไม่ทำงานเนื่องจาก Observable ที่เราทำการ Subscribe ไว้นั้นเกิด Error

Ex.2

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";

ObservableWWW.Get(errorUrl)
             .CatchIgnore((Exception ex) =>
              {
                 Debug.Log("CatchIgnore");
              }).DoOnError((Exception ex) =>
              {
                 Debug.Log("DoOnError");
              }).Subscribe((obj) => Debug.Log("Subscribe"));

จากตัวอย่าง หากเรามีการเรียกใช้ Operator CatchIgnore ก่อนที่จะมีการเรียกใช้ Operator DoOnError , Operator DoOnError นั้นจะไม่ทำงาน เนื่องมาจากใน Operator CatchIgnore นั้น จะไม่มีการ throw exception ออกมากอีก โดยเห็นได้จากภาพตัวอย่างว่า ใน Console นั้น ผลลัพธ์ที่แสดงอยู่จะไม่มีคำว่า DoOnError แต่จะมีเพียงคำว่า CatchIgnore เท่านั้น

Ex.3

string url = "https://www.google.co.th/";
string errorUrl = url + "404/";

ObservableWWW.Get(errorUrl)
             .DoOnError((Exception ex) =>
             {
                Debug.Log("DoOnError");
             }).CatchIgnore((Exception ex) =>
             {
                Debug.Log("CatchIgnore");
             }).Subscribe((obj) => Debug.Log("Subscribe"));

กลับกัน หากเรามีการเรียกใช้ Operator CatchIgnore หลังจาก Operator DoOnError , Operator ทั้งสองอันจะทำงานด้วยกันทั้งคู่ตามลำดับ