RxJS (Reactive Extensions for JavaScript) লাইব্রেরি অনেক ধরনের Utility Operators সরবরাহ করে, যা ডেটা স্ট্রিমগুলোর ওপর নির্দিষ্ট কার্যাবলী সম্পাদন করতে ব্যবহৃত হয়। এই অপারেটরগুলো বিশেষভাবে স্ট্রিমের সাথে সম্পর্কিত নির্দিষ্ট কাজগুলো সম্পাদন করতে সহায়ক, যেমন সাবস্ক্রিপশন পরিচালনা, সাবস্ক্রিপশন বন্ধ করা, স্ট্রিম নিয়ে কাজ করা, এবং ডেটা পরিবর্তন বা প্রসেস করা। RxJS-এর Utility Operators স্ট্রিমের কার্যক্ষমতা আরও বৃদ্ধি করতে সাহায্য করে।
এখানে কিছু গুরুত্বপূর্ণ Utility Operators নিয়ে আলোচনা করা হলো।
1. tap()
tap() অপারেটরটি মূলত একটি side-effect অপারেটর, যা একটি Observable-এর মানের উপর কোনো পরিবর্তন ছাড়াই সাইড এফেক্ট (যেমন লোগিং, ডিবাগিং) পরিচালনা করে। এটি স্ট্রিমের ডেটাকে সম্পূর্ণভাবে বজায় রাখে এবং শুধু কোডের অতিরিক্ত কাজ সম্পাদন করে।
বৈশিষ্ট্য:
- এটি ডেটাকে পরিবর্তন না করে নির্দিষ্ট কার্যকলাপ (যেমন, লোগিং বা ট্র্যাকিং) করতে সাহায্য করে।
- এটি side-effect হিসেবেই কাজ করে, অর্থাৎ, Observable এর ডেটার মানে কোনো পরিবর্তন আনবে না।
উদাহরণ:
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
const observable = of(1, 2, 3);
observable.pipe(
tap(value => console.log('Side effect:', value)) // লোগিং হবে কিন্তু ডেটা পরিবর্তিত হবে না
).subscribe(value => console.log('Value:', value));
এখানে, tap() অপারেটরটি শুধুমাত্র ডেটার মানের জন্য সাইড এফেক্ট (লোগিং) তৈরি করছে, কিন্তু ডেটা বদলাবে না। আউটপুট হবে:
Side effect: 1
Value: 1
Side effect: 2
Value: 2
Side effect: 3
Value: 3
2. finalize()
finalize() অপারেটরটি Observable-এর স্ট্রিম শেষ হওয়ার পরে কার্যকর হয়, অর্থাৎ যখন Observable complete() বা error() হ্যান্ডলার কল করে। এটি একটি cleanup অপারেটর হিসেবে ব্যবহৃত হয়, যেখানে আপনি রিসোর্স ফ্রি বা ক্লোজিং কার্যক্রম সম্পাদন করতে পারেন (যেমন, ইভেন্ট লিসেনার অপসারণ, সার্ভার সংযোগ বন্ধ করা ইত্যাদি)।
বৈশিষ্ট্য:
- এটি Observable স্ট্রিমের শেষে, complete() বা error() এর পর কল হয়।
- এটি cleanup অথবা ক্লিন-আপ কার্যক্রমের জন্য উপযুক্ত।
উদাহরণ:
import { of } from 'rxjs';
import { finalize } from 'rxjs/operators';
const observable = of(1, 2, 3);
observable.pipe(
finalize(() => console.log('Observable completed or errored'))
).subscribe({
next: value => console.log('Value:', value),
complete: () => console.log('Stream completed!')
});
এখানে, finalize() ব্যবহার করা হয়েছে যাতে স্ট্রিম শেষ হওয়ার পর একটি ক্লিন-আপ কার্যক্রম (যেমন লোগিং) সম্পন্ন করা হয়। আউটপুট হবে:
Value: 1
Value: 2
Value: 3
Stream completed!
Observable completed or errored
3. delay()
delay() অপারেটরটি একটি নির্দিষ্ট সময় পর ডেটার মানকে সাবস্ক্রাইবারের কাছে পাঠাতে ব্যবহৃত হয়। এটি সাধারনত ইউজারের ইন্টারঅ্যাকশন বা কিছু ইভেন্টের পরে ডেটার প্রাপ্তির জন্য ব্যবহৃত হয়। এটি সাধারণত কোনো ধরনের লেটেন্সি বা ডিলে অ্যাড করতে ব্যবহৃত হয়।
বৈশিষ্ট্য:
- এটি সাবস্ক্রাইবারের কাছে পাঠানোর আগে ডেটাকে কিছু সময় বিলম্বিত করে।
- এটি time-based scheduling এর জন্য কার্যকরী।
উদাহরণ:
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
const observable = of('Hello', 'World');
observable.pipe(
delay(2000) // ২০০০ মিলিসেকেন্ড অপেক্ষা করবে
).subscribe(value => console.log(value));
এখানে, delay(2000) ডেটাকে ২০০০ মিলিসেকেন্ড (২ সেকেন্ড) বিলম্বিত করে পাঠাচ্ছে। আউটপুট হবে:
Hello
World
এটি দুই সেকেন্ডের পরে প্রিন্ট হবে।
4. merge()
merge() অপারেটরটি একাধিক Observable কে একত্রিত করে একটি একক Observable তৈরি করতে ব্যবহৃত হয়। যখন একাধিক Observable এর মধ্যে ডেটা একই সময়ে আসে, তখন এই অপারেটরটি ডেটাকে একটি স্ট্রিমে মার্জ করে।
বৈশিষ্ট্য:
- একাধিক Observable কে একত্রিত করে একটি Observable তৈরি করে।
- এটি একাধিক উৎস থেকে আসা ডেটা অথবা ইভেন্টকে একসাথে গ্রহণ করতে ব্যবহৃত হয়।
উদাহরণ:
import { of, interval } from 'rxjs';
import { merge } from 'rxjs/operators';
const observable1 = interval(1000).pipe(take(3)); // ০ থেকে ২ পর্যন্ত সংখ্যা
const observable2 = of('A', 'B', 'C');
observable1.pipe(
merge(observable2) // observable1 ও observable2 কে একত্রিত করবে
).subscribe(value => console.log(value));
এখানে, merge() অপারেটরটি observable1 এবং observable2 এর মানগুলোকে একত্রিত করে একটি স্ট্রিম তৈরি করেছে। আউটপুট হবে:
0
1
2
A
B
C
5. retry()
retry() অপারেটরটি error() হ্যান্ডলার ব্যবহার করে যখন কোনো Observable ত্রুটি (error) প্রাপ্ত হয়, তখন এটি নির্দিষ্ট সংখ্যক বার পুনরায় চেষ্টা করে। এটি সাধারণত HTTP রিকোয়েস্ট বা অন্য যেকোনো নেটওয়ার্ক সংক্রান্ত ত্রুটির জন্য ব্যবহৃত হয়।
বৈশিষ্ট্য:
- এটি ত্রুটির পরে নির্দিষ্ট সংখ্যক বার Observable পুনরায় চালু করে।
- এটি নেটওয়ার্কের সমস্যা বা অস্থায়ী ত্রুটি সমাধানের জন্য উপযুক্ত।
উদাহরণ:
import { throwError } from 'rxjs';
import { retry } from 'rxjs/operators';
const observable = throwError('Error occurred');
observable.pipe(
retry(3) // তিনবার পুনরায় চেষ্টা করবে
).subscribe({
next: value => console.log(value),
error: err => console.log('Error:', err)
});
এখানে, retry(3) অপারেটরটি ত্রুটি হওয়ার পর তিনবার পুনরায় চেষ্টা করবে। আউটপুট হবে:
Error: Error occurred
সারাংশ
RxJS এর Utility Operators ডেটা স্ট্রিমের সাথে সম্পর্কিত বিভিন্ন কার্যাবলী সম্পাদন করতে সহায়তা করে। যেমন tap() দিয়ে সাইড এফেক্টস ম্যানেজ করা, finalize() দিয়ে ক্লিন-আপ কার্যক্রম করা, delay() দিয়ে ডেটার সময় বিলম্বিত করা, merge() দিয়ে একাধিক Observable একত্রিত করা, এবং retry() দিয়ে ত্রুটির পরে পুনরায় চেষ্টা করা। এই অপারেটরগুলো RxJS এর শক্তিশালী ফিচার, যা অ্যাসিঙ্ক্রোনাস ডেটা স্ট্রিমের সাথে আরও কার্যকরভাবে কাজ করতে সাহায্য করে।
RxJS (Reactive Extensions for JavaScript) একটি শক্তিশালী লাইব্রেরি যা অ্যাসিঙ্ক্রোনাস ডেটা এবং ইভেন্ট স্ট্রিমের সাথে কাজ করতে ব্যবহৃত হয়। tap() অপারেটরটি একটি বিশেষ ধরনের অপারেটর, যা মূল Observable এর ডেটা প্রক্রিয়াকরণের সময় কোন পরিবর্তন ছাড়া সাইড-ইফেক্ট (side-effects) বা লোকাল অপারেশন করতে ব্যবহৃত হয়। এটি মূল স্ট্রিমের ডেটাকে পরিবর্তন না করে শুধুমাত্র side-effects পরিচালনা করতে সাহায্য করে, যেমন লগিং, পর্যালোচনা, বা ডিবাগিং।
tap() অপারেটরটি ডেটার মাধ্যমে কিছু কাজ করার জন্য ব্যবহৃত হয় যেমন ডেটা রেকর্ড করা বা কনসোল লগ করা, কিন্তু এটি মূল স্ট্রিমে কোনো পরিবর্তন আনে না। এটি side-effect অপারেটর হিসেবে পরিচিত।
tap() এর বৈশিষ্ট্য
- Side Effects:
tap()মূল Observable এর ডেটাতে কোনো পরিবর্তন না এনে, সেটির সাইড-ইফেক্ট তৈরি করে (যেমন লগিং, ডিবাগিং, অথবা সিস্টেমে কিছু রেকর্ড করা)। - Non-modifying: এটি স্ট্রিমের ডেটা বা তার আচরণ পরিবর্তন করে না। যেহেতু এটি শুধুমাত্র "side effect" তৈরি করে, তাই মূল Observable অপরিবর্তিত থাকে।
- Debugging: এটি ডিবাগিং বা ডেটার অস্থায়ী পরীক্ষা করার জন্য খুবই উপকারী।
tap() এর সাইনাট
tap(nextFn: (value: T) => void, errorFn?: (error: any) => void, completeFn?: () => void): Observable<T>
এখানে:
- nextFn: ডেটা প্রতি স্ট্রিমে চলে গেলে এটি কল হবে।
- errorFn: যদি কোনো ত্রুটি ঘটে, তবে এটি কল হবে।
- completeFn: যখন স্ট্রিম শেষ হবে, তখন এটি কল হবে।
উদাহরণ: tap() দিয়ে ডেটা লগিং করা
এখানে tap() ব্যবহার করা হয়েছে ডেটার প্রক্রিয়াকরণ বা স্ট্রিমে প্রবাহিত ডেটার উপর কোনো কাজ (যেমন লগিং) করতে।
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
const observable = of(1, 2, 3);
observable.pipe(
tap(value => console.log(`Logging value: ${value}`)) // Log each emitted value
).subscribe();
আউটপুট:
Logging value: 1
Logging value: 2
Logging value: 3
এখানে, tap() অপারেটরটি শুধুমাত্র ডেটার প্রতি মানের জন্য লগ তৈরি করছে। মূল Observable (of(1, 2, 3)) অপরিবর্তিত রয়ে গেছে, এবং ডেটা শুধুমাত্র কনসোলে প্রদর্শিত হচ্ছে।
উদাহরণ: tap() দিয়ে ডিবাগিং করা
tap() অপারেটরটি ডিবাগিংয়ের জন্য অত্যন্ত কার্যকরী হতে পারে। এটি ডেটার প্রতি স্ট্রিমে কি ঘটছে তা দেখার জন্য সাহায্য করতে পারে।
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
const observable = of(5, 10, 15);
observable.pipe(
tap(value => {
if (value > 10) {
console.log(`Value is greater than 10: ${value}`);
}
})
).subscribe(value => console.log(`Received value: ${value}`));
আউটপুট:
Received value: 5
Received value: 10
Value is greater than 10: 15
Received value: 15
এখানে, tap() অপারেটরটি প্রতিটি মানের জন্য একটি শর্ত পরীক্ষা করছে (যেমন মানটি ১০ এর বেশি কিনা) এবং সেই অনুযায়ী একটি সাইড-ইফেক্ট তৈরি করছে (কনসোলে একটি বার্তা প্রিন্ট করছে)।
উদাহরণ: tap() দিয়ে স্টেট ম্যানেজমেন্ট বা লগিং
কখনও কখনও, আপনি ডেটা স্ট্রিমের সাথে সাথে কিছু লোকাল স্টেট আপডেট করতে চান, যেমন ডেটা রেকর্ড করা বা ট্র্যাকিং। tap() এই কাজের জন্য উপযুক্ত।
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
let localState = 0;
const observable = of(1, 2, 3, 4);
observable.pipe(
tap(value => {
localState += value; // Update local state on each value
console.log(`Current state: ${localState}`);
})
).subscribe();
আউটপুট:
Current state: 1
Current state: 3
Current state: 6
Current state: 10
এখানে, tap() ব্যবহার করে আমরা প্রতি স্ট্রিমের মানের উপর ভিত্তি করে একটি লোকাল স্টেট আপডেট করছি এবং তা কনসোলে লগ করছি। এইভাবে, স্ট্রিমের ওপর কোনো পরিবর্তন না এনে সাইড-ইফেক্ট তৈরি করা যায়।
tap() এবং Error Handling
tap() অপারেটরটি error handling এর সময়ও ব্যবহার করা যেতে পারে। যখন কোন Observable ত্রুটি ঘটায়, তখন আপনি tap() দিয়ে ত্রুটির তথ্য লগ করতে পারেন বা অন্য কোনো সাইড-ইফেক্ট তৈরি করতে পারেন।
import { throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
const observable = throwError('An error occurred');
observable.pipe(
tap({
error: (err) => console.log(`Error occurred: ${err}`),
}),
catchError(err => {
console.log('Caught error and recovering...');
return throwError(() => new Error('Handling the error'));
})
).subscribe({
next: value => console.log(value),
error: err => console.log(`Final Error: ${err.message}`),
});
আউটপুট:
Error occurred: An error occurred
Caught error and recovering...
Final Error: Handling the error
এখানে, tap() ত্রুটির প্রেক্ষিতে কনসোলে লগ তৈরি করেছে, এবং catchError() ত্রুটি হ্যান্ডল করেছে।
সারাংশ
tap()অপারেটরটি side-effects তৈরি করতে ব্যবহৃত হয়, যেমন লগিং, ডিবাগিং, বা লোকাল স্টেট আপডেট করা। এটি Observable এর ডেটাকে পরিবর্তন করে না, তবে এটি ডেটার প্রতি কিছু কার্যক্রম পরিচালনা করতে সাহায্য করে।- এটি non-modifying, অর্থাৎ মূল স্ট্রিমে কোনো পরিবর্তন আনে না।
tap()মূলত debugging, logging, state management, বা error logging এর জন্য ব্যবহৃত হয়।
RxJS-এ tap() অপারেটরটি খুবই উপকারী যখন আপনি স্ট্রিমের মান বা প্রক্রিয়াকরণ পর্যবেক্ষণ করতে চান এবং এর উপর কোনো পরিবর্তন ছাড়া কিছু কাজ করতে চান।
RxJS-এর মধ্যে delay(), timeout(), এবং repeat() অপারেটরগুলো অ্যাসিঙ্ক্রোনাস ডেটা স্ট্রিমে সময়সীমা এবং পুনরাবৃত্তি নিয়ন্ত্রণের জন্য ব্যবহৃত হয়। এগুলি বিশেষ করে যখন আপনি ডেটা স্ট্রিমের গতি নিয়ন্ত্রণ করতে চান বা কোনো স্ট্রিম পুনরায় চালু করতে চান, তখন বেশ কার্যকরী হয়। এই অপারেটরগুলোর ব্যবহার বুঝতে হলে, আপনি কীভাবে ডেটার স্ট্রিমে নির্দিষ্ট সময়ের জন্য বিরতি বা বিলম্ব যোগ করতে পারেন, বা নির্দিষ্ট সময় পর স্ট্রিম পুনরাবৃত্তি করতে পারেন, তা জানতে হবে।
1. delay() অপারেটর
delay() অপারেটরটি একটি নির্দিষ্ট সময় (মিলিসেকেন্ডে) পর্যন্ত একটি Observable এর মানকে বিলম্বিত (delay) করে। এটি সাধারণত ইউজার ইন্টারফেস বা কোনো টাইমিং সম্পর্কিত কার্যক্রমের জন্য ব্যবহার করা হয়, যেখানে ডেটা বা ইভেন্টের মধ্যে একটি নির্দিষ্ট বিলম্ব চাই।
উদাহরণ:
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
const observable = of('Hello', 'World').pipe(
delay(2000) // ২ সেকেন্ড পর প্রতিটি মান পাঠাবে
);
observable.subscribe(val => console.log(val));
ব্যাখ্যা:
এখানে, delay(2000) অপারেটরটি ২ সেকেন্ড পরে Hello এবং World মান দুটি সাবস্ক্রাইবারকে পাঠাবে। এর মানে হলো, delay() ব্যবহার করে আপনি ডেটা পাঠানোর সময় বিলম্ব যোগ করতে পারেন।
আউটপুট:
Hello
World
বিলম্ব: ২ সেকেন্ড
2. timeout() অপারেটর
timeout() অপারেটরটি একটি নির্দিষ্ট সময়সীমার মধ্যে Observable থেকে ডেটা গ্রহণের জন্য ব্যবহৃত হয়। যদি নির্দিষ্ট সময়সীমার মধ্যে ডেটা না পাওয়া যায়, তাহলে এটি একটি ত্রুটি (error) তৈরি করে। এটি সাধারণত HTTP রিকোয়েস্ট বা ইউজার ইনপুটের ক্ষেত্রে ব্যবহৃত হয়, যেখানে আপনি চান যে কোনো ডেটা সঠিক সময়ের মধ্যে আসুক।
উদাহরণ:
import { of } from 'rxjs';
import { timeout } from 'rxjs/operators';
const observable = of('Hello', 'World').pipe(
timeout(1000) // ১ সেকেন্ডের মধ্যে ডেটা আসতে হবে
);
observable.subscribe({
next: val => console.log(val),
error: err => console.log('Error:', err)
});
ব্যাখ্যা:
এখানে, timeout(1000) অপারেটরটি ১ সেকেন্ডের মধ্যে ডেটা আসা নিশ্চিত করবে। যদি ১ সেকেন্ডের মধ্যে কোনো ডেটা না আসে, তাহলে এটি একটি ত্রুটি পাঠাবে। তবে এই উদাহরণে, আমরা প্রিসেট ডেটা ('Hello', 'World') ব্যবহার করেছি, সুতরাং কোনো ত্রুটি হবে না।
আউটপুট:
Hello
World
তবে যদি ডেটা না আসত, তাহলে:
Error: Timeout has occurred
3. repeat() অপারেটর
repeat() অপারেটরটি একটি Observable থেকে প্রাপ্ত মানগুলিকে পুনরাবৃত্তি করে। আপনি এটি ব্যবহার করে একটি Observable কে নির্দিষ্ট সংখ্যক বার বা ইনফিনিট বার পুনরাবৃত্তি করতে পারেন। এটি সাধারণত পুনরায় কার্যক্রম শুরু করার জন্য বা লুপ চালানোর জন্য ব্যবহৃত হয়।
উদাহরণ:
import { of } from 'rxjs';
import { repeat } from 'rxjs/operators';
const observable = of('Hello', 'World').pipe(
repeat(3) // ৩ বার পুনরাবৃত্তি করবে
);
observable.subscribe(val => console.log(val));
ব্যাখ্যা:
এখানে, repeat(3) অপারেটরটি 'Hello' এবং 'World' মানগুলোকে ৩ বার পুনরাবৃত্তি করবে। ফলস্বরূপ, এটি ৬টি মান সাবস্ক্রাইবারকে পাঠাবে।
আউটপুট:
Hello
World
Hello
World
Hello
World
সারাংশ
| অপারেটর | বর্ণনা | ব্যবহার |
|---|---|---|
delay() | একটি নির্দিষ্ট সময় (মিলিসেকেন্ড) পর Observable এর মান পাঠায়। | UI ইন্টারঅ্যাকশন বা ডেটা স্ট্রিমের মধ্যে বিলম্ব যোগ করা |
timeout() | একটি নির্দিষ্ট সময়ের মধ্যে Observable থেকে ডেটা আসতে না পারলে ত্রুটি (error) তৈরি করে। | নির্দিষ্ট সময়ের মধ্যে ডেটা আসা নিশ্চিত করতে ব্যবহৃত হয় |
repeat() | Observable এর মানগুলো নির্দিষ্ট সংখ্যক বার বা অনির্দিষ্টভাবে পুনরাবৃত্তি করে। | পুনরায় কোনো কাজ বা স্ট্রিম চালানোর জন্য ব্যবহৃত হয় |
এই অপারেটরগুলি RxJS-এ সময়সীমা এবং পুনরাবৃত্তি নিয়ন্ত্রণের জন্য খুবই কার্যকরী এবং এগুলি অ্যাসিঙ্ক্রোনাস স্ট্রিমের পরিচালনায় গুরুত্বপূর্ণ ভূমিকা পালন করে।
RxJS (Reactive Extensions for JavaScript) অ্যাসিঙ্ক্রোনাস স্ট্রিম এবং ইভেন্টের মাধ্যমে কার্যকরী প্রোগ্রামিংয়ের জন্য ব্যবহৃত একটি শক্তিশালী লাইব্রেরি। finalize() অপারেটরটি RxJS-এ একটি গুরুত্বপূর্ণ ভূমিকা পালন করে, যা স্ট্রিমের পরবর্তী কাজ সম্পন্ন করার সময় cleanup বা পরিস্কার করার কাজটি সম্পন্ন করতে ব্যবহৃত হয়। যখন একটি Observable সাবস্ক্রিপশন complete বা error ঘটে, তখন finalize() অপারেটরটি কাজ করে এবং আপনি এখানে রিসোর্স ক্লিনআপ করতে পারেন যেমন টাইমার ক্লিয়ার করা, HTTP রিকোয়েস্ট বন্ধ করা, অথবা ডাটা সংরক্ষণ করা।
finalize() অপারেটর এর ব্যবহার
finalize() অপারেটরটি আপনার Observable স্ট্রিমের শেষ হওয়ার সময় cleanup কার্যক্রম সম্পাদন করার জন্য ব্যবহৃত হয়। এটি একটি callback ফাংশন গ্রহণ করে যা complete() বা error() কল হওয়ার পর চালিত হয়।
finalize() এর বৈশিষ্ট্য:
- cleanup: এটি সাধারণত রিসোর্স ক্লিনআপের জন্য ব্যবহৃত হয়, যেমন সাবস্ক্রিপশন বন্ধ করা, ইভেন্ট লিসেনার মুছে ফেলা, টাইমার ক্লিয়ার করা ইত্যাদি।
- complete() বা error() পরবর্তী: যখন Observable সম্পূর্ণ বা ত্রুটি ঘটে, তখন
finalize()এক্সিকিউট হয়। - যতবার সাবস্ক্রিপশন শেষ হবে: এটি একটি সাবস্ক্রিপশনের শেষে কার্যকরী হয়, তা সে
complete()দ্বারা শেষ হোক বাerror()দ্বারা।
finalize() এর উদাহরণ
উদাহরণ ১: complete() এর পর cleanup
import { of } from 'rxjs';
import { finalize } from 'rxjs/operators';
const observable = of('Hello', 'World').pipe(
finalize(() => console.log('Observable completed. Performing cleanup.'))
);
observable.subscribe({
next: (value) => console.log(value),
complete: () => console.log('Complete!')
});
এই উদাহরণে, finalize() অপারেটরটি complete() কল হওয়ার পর "Observable completed. Performing cleanup." বার্তা প্রদর্শন করবে। আউটপুট হবে:
Hello
World
Complete!
Observable completed. Performing cleanup.
উদাহরণ ২: error() এর পর cleanup
import { of } from 'rxjs';
import { finalize } from 'rxjs/operators';
const observable = of('Hello', 'World').pipe(
finalize(() => console.log('Observable completed or errored. Performing cleanup.'))
);
observable.subscribe({
next: (value) => {
console.log(value);
if (value === 'World') {
throw new Error('An error occurred!');
}
},
error: (err) => console.log('Error:', err),
complete: () => console.log('Complete!')
});
এখানে, World এ পৌঁছানোর পর throw দিয়ে একটি ত্রুটি তৈরি করা হচ্ছে এবং error() ব্লকের মাধ্যমে ত্রুটিটি হ্যান্ডেল করা হচ্ছে। তারপর finalize() ত্রুটি হওয়ার পরেও কার্যকরী হবে। আউটপুট হবে:
Hello
World
Error: An error occurred!
Observable completed or errored. Performing cleanup.
এখানে দেখানো হয়েছে যে, finalize() ত্রুটি ঘটলেও কার্যকরী হয়ে পরিষ্কারকরণ কাজ করবে।
finalize() ব্যবহার করার সাধারণ কেস
- HTTP রিকোয়েস্টের পর রিসোর্স ক্লিনআপ: আপনি যখন কোনও HTTP রিকোয়েস্ট পাঠান, তখন
finalize()ব্যবহার করে আপনি HTTP রিকোয়েস্টের পর ডাটা ক্লিনআপ বা UI আপডেট করতে পারেন। - টাইমার বন্ধ করা: যদি আপনি কোনও টাইমার চালাচ্ছেন, তবে Observable শেষ হলে
finalize()এর মাধ্যমে টাইমার বন্ধ করা যেতে পারে। - সাবস্ক্রিপশন বন্ধ করা: আপনি যখন একটি Observable স্ট্রিমের সাবস্ক্রিপশন ব্যবহার করছেন, তখন
finalize()ব্যবহার করে সাবস্ক্রিপশনটি বন্ধ বা ক্লিনআপ করতে পারেন।
সারাংশ
RxJS-এ finalize() অপারেটরটি ব্যবহৃত হয় একটি Observable স্ট্রিমের শেষ হওয়ার সময় cleanup কার্যক্রম সম্পন্ন করার জন্য। এটি complete() বা error() এর পরে এক্সিকিউট হয় এবং সাধারণত রিসোর্স ক্লিনআপ, ইভেন্ট লিসেনার মুছে ফেলা, টাইমার বন্ধ করা বা অন্যান্য প্রয়োজনীয় পরিস্কারকরণ কার্যক্রমের জন্য ব্যবহৃত হয়। finalize() অপারেটরটি আপনার কোডকে আরও নিরাপদ এবং কার্যকরী করে তোলে, বিশেষ করে যখন অ্যাসিঙ্ক্রোনাস স্ট্রিমের রিসোর্স পরিচালনার কথা আসে।
RxJS (Reactive Extensions for JavaScript) একটি শক্তিশালী লাইব্রেরি, যা অ্যাসিঙ্ক্রোনাস ডেটা স্ট্রিম এবং ইভেন্ট পরিচালনার জন্য ব্যবহৃত হয়। এটি ডেটার স্ট্রিমের সাথে কাজ করতে বিভিন্ন Utility Operators প্রদান করে, যা আপনার অ্যাসিঙ্ক্রোনাস স্ট্রিমকে সহজে পরিচালনা করতে সাহায্য করে।
এখানে Observable Lifecycle Management-এর জন্য কিছু গুরুত্বপূর্ণ Utility Operators এবং তাদের ব্যবহার আলোচনা করা হবে।
1. tap() অপারেটর
tap() অপারেটরটি একটি side effect তৈরি করতে ব্যবহৃত হয়, যা Observable এর স্ট্রিমের ওপর কোনো পরিবর্তন ছাড়াই অপারেশন সম্পাদন করে। এটি সাধারণত ডিবাগিং, লগিং বা এক্সটার্নাল প্রক্রিয়া (যেমন, ইউজার ইন্টারফেসের আপডেট বা মেট্রিক সংগ্রহ) করার জন্য ব্যবহৃত হয়, যখন মূল স্ট্রিমের মানে কোনো পরিবর্তন আনতে না হয়।
বৈশিষ্ট্য:
- Side Effect: স্ট্রিমের সাথে কোনো পরিবর্তন ছাড়াই অপারেশন সম্পাদন করতে পারে (যেমন লগিং বা ডিবাগিং)।
- Observable Chain-এ কোন পরিবর্তন আসে না, কেবলমাত্র side effect সম্পাদিত হয়।
উদাহরণ:
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
const observable = of(1, 2, 3, 4);
observable.pipe(
tap(value => console.log(`Intercepted value: ${value}`)) // Logging the values without modifying the stream
).subscribe(value => console.log(`Received value: ${value}`));
আউটপুট:
Intercepted value: 1
Received value: 1
Intercepted value: 2
Received value: 2
Intercepted value: 3
Received value: 3
Intercepted value: 4
Received value: 4
এখানে, tap() অপারেটরটি স্ট্রিমের মানগুলি লগ করছে, তবে স্ট্রিমের মূল ডেটা পরিবর্তিত হচ্ছে না।
2. finalize() অপারেটর
finalize() অপারেটরটি Observable স্ট্রিমের শেষে কিছু কার্যকলাপ (cleanup) সম্পাদন করার জন্য ব্যবহৃত হয়। এটি Observable lifecycle শেষ হওয়ার পর, অর্থাৎ স্ট্রিমটি সম্পূর্ণ হওয়া অথবা ত্রুটি ঘটার পর কার্যকর হয়। এটি সাধারণত অ্যাসিঙ্ক্রোনাস কাজের পর ক্লিন-আপ বা রিসোর্স ফ্রি করার জন্য ব্যবহার করা হয়।
বৈশিষ্ট্য:
- Cleanup: Observable স্ট্রিমের শেষে ক্লিন-আপ কার্যকলাপ পরিচালনা করতে ব্যবহৃত হয়।
- Completion or Error: স্ট্রিমটি কমপ্লিট অথবা ত্রুটি হলে কার্যকর হয়।
উদাহরণ:
import { of } from 'rxjs';
import { finalize } from 'rxjs/operators';
const observable = of(1, 2, 3);
observable.pipe(
finalize(() => {
console.log('Observable has completed or errored!');
})
).subscribe(
value => console.log(`Received value: ${value}`),
error => console.log(`Error: ${error}`),
() => console.log('Completed')
);
আউটপুট:
Received value: 1
Received value: 2
Received value: 3
Observable has completed or errored!
Completed
এখানে, finalize() অপারেটরটি Observable স্ট্রিম সম্পূর্ণ হওয়ার পর "Observable has completed or errored!" মেসেজটি প্রিন্ট করেছে।
3. delay() অপারেটর
delay() অপারেটরটি Observable স্ট্রিমের মধ্যে নির্দিষ্ট সময়ের বিলম্ব (delay) তৈরি করতে ব্যবহৃত হয়। এটি প্রধানত time-based operations যেমন, টাইমার, ডিলে বা ইন্টারভ্যাল হ্যান্ডলিংয়ের জন্য ব্যবহৃত হয়।
বৈশিষ্ট্য:
- Time Delay: স্ট্রিমে কিছু সময়ের জন্য বিলম্ব তৈরি করে।
- Timed Operations: নির্দিষ্ট সময়ের মধ্যে কোন কাজ সম্পাদন করতে সহায়তা করে।
উদাহরণ:
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
const observable = of('Hello', 'World');
observable.pipe(
delay(1000) // 1 second delay
).subscribe(value => console.log(value));
আউটপুট:
Hello
World
এখানে, delay() অপারেটরটি ১ সেকেন্ড বিলম্বের সাথে আউটপুট দেয়।
4. retry() এবং retryWhen() অপারেটর
retry() এবং retryWhen() অপারেটরগুলি ত্রুটি (error) ঘটলে পুনরায় চেষ্টা করার জন্য ব্যবহৃত হয়। retry() নির্দিষ্ট সংখ্যক বার retry করতে সাহায্য করে, এবং retryWhen() আরও কাস্টম retry লজিক তৈরি করতে সহায়তা করে।
বৈশিষ্ট্য:
- Automatic Retries: ত্রুটি ঘটলে পুনরায় চেষ্টা করে।
- Error Recovery: অ্যাসিঙ্ক্রোনাস স্ট্রিমে error পরিস্থিতি মোকাবেলা করতে সাহায্য করে।
উদাহরণ: retry()
import { of, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
const observable = throwError('Something went wrong');
observable.pipe(
retry(2), // Retry 2 times
catchError(err => {
console.log('Caught error:', err);
return of('Recovered with fallback value');
})
).subscribe({
next: value => console.log('Received:', value),
error: err => console.log('Error:', err),
complete: () => console.log('Completed'),
});
আউটপুট:
Caught error: Something went wrong
Received: Recovered with fallback value
Completed
এখানে, retry(2) অপারেটরটি ত্রুটি হওয়ার পর ২ বার পুনরায় চেষ্টা করেছে এবং তার পরে catchError() ফালব্যাক ভ্যালু প্রদান করেছে।
5. take() এবং takeUntil() অপারেটর
take() এবং takeUntil() অপারেটরগুলি একটি নির্দিষ্ট সংখ্যা বা শর্তে Observable স্ট্রিম থেকে ডেটা নেওয়ার জন্য ব্যবহৃত হয়। take() নির্দিষ্ট সংখ্যা পর্যন্ত ডেটা নেয়, এবং takeUntil() একটি নির্দিষ্ট স্ট্রিমের মান আসা পর্যন্ত ডেটা নেয়।
বৈশিষ্ট্য:
- Limited Subscription: স্ট্রিম থেকে নির্দিষ্ট সংখ্যক বা শর্তে ডেটা গ্রহণ করা।
- Condition-based Stream Termination: নির্দিষ্ট শর্ত পূর্ণ হলে স্ট্রিম বন্ধ করা।
উদাহরণ: take()
import { of } from 'rxjs';
import { take } from 'rxjs/operators';
const observable = of(1, 2, 3, 4, 5);
observable.pipe(
take(3) // Take first 3 values
).subscribe(value => console.log(value));
আউটপুট:
1
2
3
এখানে, take(3) অপারেটরটি প্রথম ৩টি মানই সাবস্ক্রাইবে পাঠিয়েছে।
উদাহরণ: takeUntil()
import { interval, of } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
const observable = interval(1000); // Emits values every second
const notifier = of('Stop'); // Stops the stream when this emits
observable.pipe(
takeUntil(notifier) // Takes values from observable until notifier emits
).subscribe(value => console.log(value));
আউটপুট:
0
1
2
এখানে, takeUntil() যখন notifier Observable থেকে 'Stop' আসে, তখন স্ট্রিম বন্ধ হয়ে যায়।
সারাংশ
RxJS-এ Utility Operators ব্যবহার করে আপনি Observable Lifecycle সহজে ম্যানেজ করতে পারেন। এই অপারেটরগুলির মাধ্যমে আপনি ডেটার স্ট্রিমের lifecycle পরিচালনা, ডিবাগিং, ক্লিন-আপ, পুনরায় চেষ্টা এবং বিলম্ব নিয়ন্ত্রণ করতে পারেন। কয়েকটি গুরুত্বপূর্ণ utility operator এর উদাহরণ:
- tap(): Side effect তৈরি করার জন্য।
- finalize(): স্ট্রিমের শেষের ক্লিন-আপ কাজ।
- delay(): স্ট্রিমে বিলম্ব তৈরি করা।
- retry() এবং retryWhen(): error হলে পুনরায় চেষ্টা করা।
- take() এবং takeUntil(): নির্দিষ্ট সংখ্যক বা শর্ত অনুযায়ী ডেটা নেওয়া।
এই অপারেটরগুলির মাধ্যমে আপনি আপনার Observable স্ট্রিমের জীবনচক্র (Lifecycle) কার্যকরভাবে পরিচালনা করতে পারবেন।
Read more