สร้างการสมัครสมาชิกครั้งเดียว


182

ฉันต้องการสร้างการสมัครรับข้อมูลObservableที่จะถูกกำจัดทันทีเมื่อมีการโทรครั้งแรก

มีบางอย่างเช่น:

observable.subscribeOnce(func);

กรณีการใช้งานของฉันฉันกำลังสร้างการสมัครสมาชิกในตัวจัดการเส้นทางด่วนและการสมัครจะถูกเรียกหลายครั้งต่อคำขอ

คำตอบ:


319

ไม่แน่ใจ 100% เกี่ยวกับสิ่งที่คุณต้องการ แต่ถ้าคุณต้องการสังเกตค่าแรกให้ใช้อย่างใดอย่างหนึ่งfirst()หรือtake(1):

observable.first().subscribe(func);

หมายเหตุ: .take(1)และ.first()ทั้งสองอย่างจะยกเลิกการเป็นสมาชิกโดยอัตโนมัติเมื่อตรงตามเงื่อนไข

อัปเดตจาก RxJS 5.5+

จากความคิดเห็นโดยCoderer

import { first } from 'rxjs/operators'

observable
  .pipe(first())
  .subscribe(func);

นี่คือเหตุผล


33
การสมัครสมาชิกจะได้รับการทำความสะอาดโดยอัตโนมัติหลังจากหรือไม่
Berkeley Martinez

50
ใช่แล้ว. รับและยกเลิกทั้งสองอย่างก่อนเมื่อมีคุณสมบัติตรงตามเงื่อนไข
Brandon

20
ทำไมเอกสารไม่บอกว่ามันถูกยกเลิกการสมัครโดยอัตโนมัติ?
jzig

17
เป็นกฎทั่วไปของ RxJS ที่การสมัครสมาชิกจะถูกกำจัดเมื่อสตรีมที่สังเกตได้สิ้นสุดลง ซึ่งหมายความว่าโอเปอเรเตอร์ใด ๆ ที่ "ย่อ" สตรีม (หรือแปลงเป็นสตรีมประเภทอื่น) จะยกเลิกการสมัครจากสตรีมต้นทางเมื่อการดำเนินการเสร็จสิ้น ฉันไม่แน่ใจว่ามีการระบุไว้ในเอกสารประกอบหรือไม่
Brandon

37
ถ้าใครกำลังจะมาถึงในปี 2018 ที่คุณต้องการจริงobservable.pipe(first()).subscribe(func)ที่มาจากfirst rxjs/operators
Coderer

32

RxJS มีเอกสารที่ดีที่สุดที่ฉันเคยเจอ การติดตามลิงก์ร้องจะนำคุณไปสู่กรณีการใช้งานการแมปตารางที่เป็นประโยชน์อย่างยิ่งแก่ผู้ประกอบการ ยกตัวอย่างเช่นภายใต้ "ฉันต้องการที่จะใช้ค่าแรก" กรณีใช้เป็นสามผู้ประกอบการ: first, และfirstOrDefaultsample

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

การค้นหาตัวดำเนินการใช้ตัวดำเนินการ


3

หากคุณต้องการเรียกใช้ Observable เพียงครั้งเดียวก็หมายความว่าคุณจะไม่รอกระแสข้อมูลจากมัน ดังนั้นการใช้toPromise()แทนที่จะsubscribe()เพียงพอในกรณีของคุณเนื่องจากtoPromise()ไม่จำเป็นต้องยกเลิกการสมัคร


ที่น่าสนใจมากนี้ยังหมายถึงการที่เราสามารถทำได้เพียงแค่ซึ่งจะทำให้มันเป็นหนึ่งในสายการบินawaitpromise
หลุย Almeda

@ LouieAlmeda คุณช่วยยกตัวอย่างหนึ่งซับให้เราได้ไหม?
Ado Ren

สวัสดี @AdoRen ฉันได้อธิบายเทคนิคในคำตอบที่นี่สำหรับคุณฉันหวังว่าจะช่วย
Louie Almeda

2

เพื่อเสริม@ คำตอบของแบรนดอนใช้first()หรือชอบนอกจากนี้ยังเป็นสิ่งจำเป็นสำหรับการปรับปรุงบนพื้นฐานของBehaviorSubject Observableตัวอย่าง (ยังไม่ได้ทดสอบ):

var subject = new BehaviorSubject({1:'apple',2:'banana'});
var observable = subject.asObservable();

observable
  .pipe(
    first(), // <-- Ensures no stack overflow
    flatMap(function(obj) {
      obj[3] = 'pear';
      return of(obj);
    })
  )
  .subscribe(function(obj) {
    subject.next(obj);
  });

2

เวอร์ชั่นที่สะอาดและสะดวกสบาย

การขยายคำตอบที่น่าอัศจรรย์ของ M Fuat NUROĞLUในการแปลงคำสัญญาที่สังเกตได้เป็นนี่เป็นรุ่นที่สะดวกมาก

const value = await observable.toPromise();

console.log(value)

ความงามของสิ่งนี้คือเราสามารถใช้ค่านั้นเหมือนตัวแปรปกติโดยไม่ต้องแนะนำบล็อกที่ซ้อนกันอีก!

สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อคุณต้องการรับค่าหลายค่าจากการสังเกตได้หลายค่า เรียบร้อยและสะอาด

const content = await contentObservable.toPromise();
const isAuthenticated = await isAuthenticatedObservable.toPromise();

if(isAuthenticated){
   service.foo(content)
}

แน่นอนคุณจะต้องทำให้ฟังก์ชั่นที่มีของคุณasyncถ้าคุณจะไปกับเส้นทางนี้ คุณสามารถทำ.thenตามสัญญาได้หากคุณไม่ต้องการให้ฟังก์ชั่นที่มีอยู่เป็นแบบอะซิงก์

ฉันไม่แน่ใจว่ามีการแลกเปลี่ยนกับวิธีการนี้หรือไม่โปรดแจ้งให้เราทราบในความคิดเห็นเพื่อที่เราจะได้ทราบ

ป.ล. ถ้าคุณชอบคำตอบนี้อย่าลืมตอบคำถามของ M Fuat NUROĞLUด้วย :)


0

ฉันมีคำถามที่คล้ายกัน

ด้านล่างนี้ถูกเรียกใช้ในภายหลังจากผู้เปลี่ยนสถานะที่แตกต่างกัน อย่างที่ฉันไม่ต้องการ

function foo() {
    // this was called many times which was not needed
    observable.subscribe(func);
    changeObservableState("new value");
}

ฉันตัดสินใจลองunsubscribe()สมัครหลังจากด้านล่าง

function foo() {
    // this was called ONE TIME
    observable.subscribe(func).unsubscribe();
    changeObservableState("new value");
}

subscribe(func).unsubscribe();subscribeOnce(func)เป็นเหมือน

ฉันหวังว่าจะช่วยคุณเช่นกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.