Dalam artikel sebelumnya , kami melihat cara membuat pernyataan RxJS kami sendiri. Sekarang saya ingin berbicara tentang operator pembuatan yang kurang dikenal - defer- dan menjelaskan bagaimana Anda dapat menggunakannya untuk beberapa situasi
Misalkan Anda perlu membuat operator yang mengambil fungsi dan mengeksekusi hanya sekali, pertama kali menerima nilai. Kami menerapkannya di bawah nama tapOnce
function tapOnce<T>(fn: Function): OperatorFunction<T, T> {
return function(source: Observable<any>) {
let run = false;
return source.pipe(
tap(() => {
if (!run) {
fn();
run = true;
}
})
);
};
}
Kode ini jelas - tapdigunakan untuk menjalankan fungsi, bendera hanya runperlu dilakukan sekali. Sekarang kita menggunakan operator.
const source = interval(5000).pipe(
tapOnce(() => console.log('+')
));
source.subscribe(console.log);
Semuanya berfungsi, tanda plus ditampilkan di konsol hanya di emite pertama. Sekarang tambahkan pelanggan.
const source = interval(5000).pipe(
tapOnce(() => console.log('+')
));
source.subscribe(console.log);
source.subscribe(console.log);
Jika Anda melihat konsol - hanya ada satu plus. Masalahnya adalah bahwa kedua pelanggan menggunakan lingkungan leksikal yang sama dan merujuk ke variabel yang sama run. Kami membutuhkan cara untuk menunda pembuatan utas sampai seseorang berlangganan.
Akan membantu defer
import { defer } from 'rxjs';
function tapOnce<T>(fn: Function): OperatorFunction<T, T> {
return function(source: Observable<any>) {
return defer(() => {
let run = false;
return source.pipe(
tap(() => {
if (!run) {
fn();
run = true;
}
})
);
});
};
}
Operator defermenerima fungsi yang harus kembali ObservableInput. Kode di dalam deferakan dieksekusi hanya setelah berlangganan, dan tidak selama pembuatan. Menggunakan pendekatan ini dan terima kasih kepada penutupan js, masing-masing pelanggan menggunakan lingkungan leksikal sendiri.
Mari kita buat implementasi sederhana kami deferuntuk pemahaman yang lebih baik.
function defer(observableFactory: () => ObservableInput<any>) {
return new Observable(subscriber => {
const source = observableFactory();
return source.subscribe(subscriber);
});
}
defer mengembalikan aliran baru, yang dibuat pada saat berlangganan oleh fungsi pabrik, dan akan digunakan sebagai sumber.
Berikut adalah lebih banyak contoh di mana itu akan bermanfaat defer. Katakanlah kita memiliki ekspresi yang perlu dihitung ketika seseorang mendaftar. contohnya
const randNum = of(Math.random());
randNum.subscribe(console.log);
randNum.subscribe(console.log);
Dalam contoh ini, setiap pelanggan akan menerima nilai acak yang sama. Anda dapat memperbaikinya sehingga ekspresi dihitung saat berlangganan, bukan saat mengumumkan.
const randNum = defer(() => of(Math.random()));
randNum2.subscribe(console.log);
randNum2.subscribe(console.log);
const randNum = () => of(Math.random());
randNum2().subscribe(console.log);
randNum2().subscribe(console.log);
Contoh lain adalah ketika Anda perlu menunda pelaksanaan janji.
const promise = new Promise(resolve => {
resolve();
});
const promiseDefered = defer(() => {
return new Promise(resolve => {
resolve();
});
});
promiseDefered.subscribe(console.log);
Janji dieksekusi segera, terlepas dari jumlah pendengar. Anda dapat membuat janji terlihat seperti aliran (mis. Malas) menggunakan defer.