يجتمع تأجيل

في مقال سابق ، نظرنا في كيفية إنشاء عبارات RxJS الخاصة بنا. أريد الآن أن أتحدث عن عامل إنشاء غير معروف defer- وأشرح كيف يمكنك استخدامه لبعض المواقف


لنفترض أنك تحتاج إلى إنشاء عامل يأخذ وظيفة وينفذها مرة واحدة فقط ، في المرة الأولى التي يتلقى فيها قيمة. نقوم بتطبيقه تحت اسم 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;
        }
      })
    );
  };
}

الرمز واضح - يتم tapاستخدامه لتشغيل الوظيفة ، وهناك runحاجة إلى العلم للقيام بذلك مرة واحدة فقط. الآن نستخدم عامل التشغيل.


const source = interval(5000).pipe(
  tapOnce(() => console.log('+')
));

source.subscribe(console.log);

كل شيء يعمل ، يتم عرض علامة الجمع في وحدة التحكم فقط عند الإيماءة الأولى. أضف الآن المشتركين.


const source = interval(5000).pipe(
  tapOnce(() => console.log('+')
));

source.subscribe(console.log);
source.subscribe(console.log);

إذا نظرت إلى وحدة التحكم - هناك زائد واحد فقط. تكمن المشكلة في أن كلا المشتركين يستخدمان نفس البيئة المعجمية ويشيران إلى نفس المتغير run. نحتاج إلى طريقة لتأجيل إنشاء سلسلة رسائل حتى يشترك شخص ما.


سوف يساعد 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;
          }
        })
      );
    });
  };
}

deferيقبل عامل التشغيل دالة يجب أن تعود ObservableInput. deferسيتم تنفيذ الرمز في الداخل فقط عند الاشتراك ، وليس أثناء الإنشاء. باستخدام هذا النهج وبفضل إغلاق js ، يستخدم كل مشترك بيئته المعجمية الخاصة.


دعونا ننشئ تطبيقنا البسيط deferلفهم أفضل.


function defer(observableFactory: () => ObservableInput<any>) {
  return new Observable(subscriber => {
    const source = observableFactory();
    return source.subscribe(subscriber);
  });
}

defer إرجاع دفق جديد تم إنشاؤه في لحظة الاشتراك بواسطة وظيفة المصنع ، وسيتم استخدامه كمصدر.


هنا المزيد من الأمثلة حيث ستكون مفيدة defer. لنفترض أن لدينا تعبيرًا يجب احتسابه عند اشتراك شخص ما. على سبيل المثال


const randNum = of(Math.random());

randNum.subscribe(console.log);
randNum.subscribe(console.log);

في هذا المثال ، سيحصل كل مشترك على نفس القيمة العشوائية. يمكنك تصحيحه بحيث يتم احتساب التعبير عند الاشتراك ، وليس عند الإعلان.


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

مثال آخر هو عندما تحتاج إلى تأخير تنفيذ الوعد.


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

يتم تنفيذ الوعود على الفور ، بغض النظر عن عدد المستمعين. يمكنك أن تجعل الوعد يبدو مثل تيار (أي كسول) باستخدام defer.


All Articles