Temui defer

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);

// The same concept as using a function
const randNum = () => of(Math.random());
randNum2().subscribe(console.log);
randNum2().subscribe(console.log);

Contoh lain adalah ketika Anda perlu menunda pelaksanaan janji.


// This already executing regardless the numbers of handlers
const promise = new Promise(resolve => {
  resolve();
});

// Deferring the creation of the promise until someone subscribes
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.


All Articles