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 - tap
digunakan untuk menjalankan fungsi, bendera hanya run
perlu 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 defer
menerima fungsi yang harus kembali ObservableInput
. Kode di dalam defer
akan 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 defer
untuk 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
.