ค้นหาเว็บไซต์

angular - วิธีรอ Observable ที่เป็นตัวเลือก


ในแอป Angular ของฉัน ฉันกำลังทำการเรียก HTTP แบบไม่จำเป็นเพื่อตรวจสอบว่าผู้ใช้มีอยู่หรือไม่ ซึ่งขึ้นอยู่กับผลลัพธ์ของการเรียกนี้ ฉันต้องการจะเรียกอีกการเรียกหนึ่งหรือหยุดการประมวลผล โดยไม่ใช้ .toPromise() ฉันจะสามารถรอการเรียกที่ทำในบล็อก if ได้อย่างไร?

  onSomeEvent() {
    const contact: IContact = {
      ...this.userForm.value
    };

    let cancelProcessing = false;

    if (this.isNewUser()) {
      // *** This is optional
      this.userService.duplicateUserSearch(contact.email, contact.userName)
        .subscribe(result => {
          if (result.result !== '') {
            cancelProcessing = true;
          }
        });
    }

    // *** This statement is hit before the observable completes
    if (cancelProcessing) {
      return;
    }

    //  *** which means that this runs when it shouldn't
    this.userService.updateContact(contact)
      .subscribe(res => {
        this.activeModal.close(res);
      });
  }

คำตอบ #1

อย่างที่คุณแสดงด้วยคำถามของคุณ การใช้ตรรกะ If/Then กับ Observables อาจซับซ้อนได้ มีการอภิปรายที่ดีเกี่ยวกับเรื่องนี้ที่นี่

คุณได้รับคำตอบมาบ้างแล้วที่อาจใช้ได้ภายใต้เงื่อนไขบางอย่าง และฉันก็อาจจะปล่อยไปแล้วให้คุณอยู่ในมือที่เชี่ยวชาญของแฟนหรือเจฟฟรีย์ แต่ฉันรู้สึกสนใจในความคิดเห็นที่คุณพูดต่อคำตอบหนึ่งว่า: "จะเกิดอะไรขึ้นถ้าฉันเพิ่มเงื่อนไขมากขึ้น?" นั่นดึงดูดความสนใจของฉัน ดังนั้นฉันจึงอยากหาลวดลายที่สามารถสังเกตหรือใช้งานได้จริง อ่านเข้าใจง่าย และสามารถขยายได้ง่ายถ้าคุณตัดสินใจเพิ่มเงื่อนไขเพิ่มเติมในภายหลัง คำถามดี ๆ ทำให้ฉันคิดอย่างหนัก และคุณก็ทำให้ฉันคิดแน่นอน :)

ฉันได้ลองประยุกต์ใช้รูปแบบที่แนะนำในบทความที่ฉันลิงก์ไว้ข้างต้นกับปัญหาของคุณ และโค้ดด้านล่างคือสิ่งที่ฉันคิดออก ตามที่ฉันได้กล่าวไว้ในความคิดเห็นต่อคำถามดั้งเดิมของคุณข้างต้น ฉันไม่แน่ใจ 100% ว่าคุณต้องการให้ข้อมูลผู้ติดต่อได้รับการอัปเดตเมื่อผู้ใช้ไม่ใช่ผู้ใช้ใหม่ แต่ตอนนี้ฉันสมมติว่าคุณต้องการเช่นนั้น ข้อจำกัดความรับผิด: ฉันยังไม่ได้ทดสอบอย่างเข้มงวด เช่น การสร้าง Stackblitz และสร้างกรณีทดสอบต่างๆ แม้ว่านั่นจะเป็นวิธีที่ฉันมักจะต้องการตอบคำถามแบบนี้ ดังนั้นขออภัยหากมีข้อบกพร่องหรือผลลัพธ์ที่ไม่ตั้งใจในโค้ดด้านล่าง โอ้ วันหยุดสุดสัปดาห์กำลังเรียกร้องอยู่ ;)

ในรูปแบบนั้นในบทความมีการแนะนำให้สร้างสาขาสำหรับทุกเส้นทางที่เป็นไปได้ผ่านตรรกะ if/then ฉันได้คิดถึงสองสาขาหลักที่จะนำไปสู่การเรียกใช้ updateContact() โปรดทราบว่าในรูปแบบนี้สามารถเพิ่ม tap() ในสาขาใดก็ได้เพื่อทำงานเพิ่มเติมหากจำเป็น หากฉันพลาดสาขาที่คุณต้องการเพิ่ม การเพิ่มสาขานั้นก็จะง่ายเช่นกัน

หัวใจของรูปแบบนี้อยู่ที่ merge() ที่ตอนท้าย ซึ่งจะสร้าง observable ตัวเดียวที่รวมสองตัวที่ส่งเข้ามาเข้าด้วยกัน หากตัวใดตัวหนึ่งเสร็จสิ้น การ subscribe จะทำงานและเรียกใช้ updateContact() ในกรณีนี้ ทั้งสองจะไม่เสร็จสิ้นพร้อมกันเพราะตัวกรอง isNewUser() ทำให้มั่นใจได้ว่าจะมีเพียงตัวหนึ่งที่ทำงาน แต่ถ้าคุณนำรูปแบบนี้ไปใช้ที่อื่น คุณอาจต้องเพิ่ม take(1) หากคุณสนใจเพียงตัวอะซิงโครนัสตัวแรกที่ 'ชนะ'

ฉันยังแสดงปุ่มสมัครรับข้อมูลและยกเลิกการสมัครด้วย เพราะฉันคิดว่านั่นเป็นแนวปฏิบัติที่ดีที่สุด

onSomeEventSub : Subscription; // component scope variable to add to later unsubscribe with

onSomeEvent() {
    const contact: IContact = {
      ...this.userForm.value
    };

    // define duplicateUserSearch$ now for easier readability below
    const duplicateUserSearch$: Observable<boolean> = 
        this.userService.duplicateUserSearch(contact.email, contact.userName).pipe(
            map(result => (result.result === '')));

    // First, create a shareable source for eventual merge of all branches.
    // of(0) is completely arbitrary.  It would be more interesting to tie
    // this to the original event, but that wasn't part of the question.  :)
    const source$ = of(0).pipe(
        share() // same observable will have multiple observers
    );

    // branch 1 is for when the user is a new user and duplicate logic asserts
    const isNewUserAndIsDupe$ = source$.pipe(
        filter(() => isNewUser()),
        mergeMap(() => duplicateUserSearch$),
        filter(res => res)
    );

    // branch 2 is when the user is NOT a new user
    const isNotNewUser$ = source$.pipe(
        filter(() => !isNewUser())
    );

    // and finally the merge that pulls this all together and subscribes
    this.onSomeEventSub = merge(isNewUserAndIsDupe$, isNotNewUser$).pipe(
        mergeMap(() => this.userService.updateContact(contact))
    ).subscribe(res => this.activeModal.close(res));

}

ngOnDestroy() {
    if (this.onSomeEventSub) this.onSomeEventSub.unsubscribe();
}

คำตอบ #2

แฟชั่นที่มีประโยชน์ใช้สอยมากขึ้น

onSomeEvent() {
  const contact: IContact = {
    ...this.userForm.value
  };
const updateContact=this.userService.updateContact(contact)
  .pipe(tap(res => {
    this.activeModal.close(res);
  }))

return of(this.isNewUser()).pipe(mergeMap(newUser=>{
   if(!newUser)
      return updateContact
   return this.userService.duplicateUserSearch(contact.email, contact.userName)
     .pipe(mergeMap(result=>result.result === ''?updateConcat:empty()))  
}))

}

// execute
this.onSomeEvent().subscribe()

บทความที่เกี่ยวข้อง