Buat langganan satu kali

182

Saya perlu membuat langganan ke Observableyang segera dibuang saat pertama kali dipanggil.

Apakah ada sesuatu seperti:

observable.subscribeOnce(func);

Kasing penggunaan saya, saya membuat langganan dalam pengendali rute ekspres dan langganan dipanggil beberapa kali per permintaan.

Berkeley Martinez
sumber

Jawaban:

319

Tidak 100% yakin tentang apa yang Anda butuhkan, tetapi jika Anda hanya ingin mengamati nilai pertama, gunakan salah satu first()atau take(1):

observable.first().subscribe(func);

catatan: .take(1)dan .first()keduanya berhenti berlangganan secara otomatis ketika kondisinya terpenuhi

Pembaruan dari RxJS 5.5+

Dari komentar oleh Coderer .

import { first } from 'rxjs/operators'

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

Inilah sebabnya

Brandon
sumber
33
Apakah langganan bisa dibersihkan secara otomatis setelah?
Berkeley Martinez
50
Ya itu. Ambil dan pertama-tama berhenti berlangganan ketika kondisinya terpenuhi.
Brandon
20
Mengapa dokumentasi tidak mengatakan bahwa itu secara otomatis membuang langganan?
jzig
17
Ini adalah aturan umum RxJS bahwa langganan dibuang ketika aliran yang dapat diamati berakhir. Itu berarti setiap operator yang "mempersingkat" aliran (atau mengubahnya menjadi jenis aliran yang berbeda) akan berhenti berlangganan dari aliran sumber ketika operasi mereka selesai. Saya tidak yakin di mana atau apakah ini dinyatakan dalam dokumentasi.
Brandon
37
Jika ada yang datang ke sini pada tahun 2018, Anda benar-benar ingin observable.pipe(first()).subscribe(func), dari mana firstdatangnya rxjs/operators.
Coderer
32

RxJS memiliki beberapa dokumentasi terbaik yang pernah saya temui. Mengikuti tautan di bawah ini akan membawa Anda ke tabel penggunaan pemetaan yang sangat membantu bagi operator. Misalnya, di bawah "Saya ingin mengambil nilai pertama" kasus penggunaan tiga operator: first, firstOrDefault, dan sample.

Catatan, jika urutan yang dapat diamati selesai tanpa pemberitahuan, maka firstoperator akan memberi tahu pelanggan tentang kesalahan sementara firstOrDefaultoperator memberikan nilai default kepada pelanggan.

pencarian kasus penggunaan operator

DetweilerRyan
sumber
3

Jika Anda ingin memanggil Observable hanya satu kali, itu berarti Anda tidak akan menunggu streaming darinya. Jadi menggunakan toPromise()bukan subscribe()akan cukup dalam kasus Anda karena toPromise()tidak perlu berhenti berlangganan.

M Fuat NUROĞLU
sumber
sangat menarik, ini juga berarti kita hanya bisa awaitsatu promiseyang menjadikannya salah satu kapal
Louie Almeda
@LouieAlmeda dapatkah Anda memberi kami contoh satu kalimat?
Ado Ren
Hai @ AdoRen, saya telah menguraikan teknik dalam jawaban di sini untuk Anda, saya harap itu membantu.
Louie Almeda
2

Untuk melengkapi jawaban @ Brandon , menggunakan first()atau sejenisnya juga penting untuk memperbarui BehaviorSubjectberdasarkan Observable. Misalnya (belum diuji):

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);
  });
Andy
sumber
2

Versi Bersih dan Nyaman

Memperluas jawaban luar biasa M Fuat NUROĞLU tentang mengonversi yang dapat diamati menjadi sebuah janji, inilah versi yang sangat nyaman.

const value = await observable.toPromise();

console.log(value)

Keindahan dari ini adalah bahwa kita dapat menggunakan nilai itu seperti variabel normal tanpa memperkenalkan blok bersarang lain!

Ini sangat berguna ketika Anda perlu mendapatkan beberapa nilai dari beberapa yang bisa diamati. Rapi dan bersih.

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

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

Tentu saja, Anda harus membuat fungsi yang mengandung asyncAnda jika Anda ingin pergi dengan rute ini. Anda juga bisa hanya .thenberjanji jika Anda tidak ingin fungsi yang mengandung async

Saya tidak yakin jika ada pengorbanan dengan pendekatan ini, jangan ragu untuk memberi tahu saya di komentar sehingga kami sadar.

PS Jika Anda menyukai jawaban ini, jangan lupa untuk mengunggah Jawaban M Fuat NUROĞLU :)

Louie Almeda
sumber
0

Saya punya pertanyaan serupa.

Di bawah ini dipanggil bahkan kemudian dari penukar negara yang berbeda. Karena saya tidak mau.

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

Saya memutuskan untuk mencoba unsubscribe()setelah berlangganan seperti di bawah ini.

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

subscribe(func).unsubscribe();seperti subscribeOnce(func).

Saya harap itu membantu Anda juga.

MrHIDEn
sumber