في مقال سابق ، نظرنا في كيفية إنشاء عبارات 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);
const randNum = () => of(Math.random());
randNum2().subscribe(console.log);
randNum2().subscribe(console.log);
مثال آخر هو عندما تحتاج إلى تأخير تنفيذ الوعد.
const promise = new Promise(resolve => {
resolve();
});
const promiseDefered = defer(() => {
return new Promise(resolve => {
resolve();
});
});
promiseDefered.subscribe(console.log);
يتم تنفيذ الوعود على الفور ، بغض النظر عن عدد المستمعين. يمكنك أن تجعل الوعد يبدو مثل تيار (أي كسول) باستخدام defer
.