Polling در جاوا اسکریپت — به زبان ساده
Polling تکنیکی است که با استفاده از آن دادههای تازه را در یک بازه مفروض با ارائه درخواستهای API دورهای به یک سرور بررسی میکنیم. برای نمونه میتوانیم از Polling برای بررسی این نکته استفاده کنیم که آیا دادهها به طور مکرر تغییر مییابند یا باید منتظر سرور بمانیم تا از یک حالت مشخص عبور کند. Polling در جاوا اسکریپت یک جایگزین ساده برای وبسوکت یا رویدادهای سرور محسوب میشود.
در این مقاله ابتدا به توضیح ماهیت Polling و زمان مناسب برای استفاده از آن میپردازیم و سپس یک تابع poll را در جاوا اسکریپت پیادهسازی میکنیم. در نهایت شیوه استفاده از این تابع را با استفاده از یک API ساختگی بررسی میکنیم.
چه زمانی باید از Polling استفاده کنیم؟
یکی از کاربردهای عملی Polling زمانی است که میخواهیم از یک ارائهدهنده شخص ثالثِ خدمات احراز هویت مانند Firebase یا Auth0 استفاده کنیم و پیش از ادامه کار باید منظر آنها بمانیم. زمانی که یک کاربر ثبت نام میکند، دادههای کاربر را از کلاینت به ارائهدهنده احراز هویت ارسال میکنیم. سپس روی سرور منتظر دریافت پاسخ از ارائهدهنده احراز هویت میمانیم و در نهایت یک کاربر در پایگاه داده ایجاد میکنیم.
در طی این فرایند، کلاینت باید منتظر احراز هویت و ایجاد کاربر در سمت سرور بماند. از آنجا که ما موفقیت یا شکست این فرایند را تقریباً در طی زمان کوتاهی متوجه میشویم، میتوانیم اقدام به پیادهسازی یک Poll کنیم که درخواستهای API را هر ثانیه یک بار تا زمانی که به فرایند ثبت نام و ایجاد کاربر جدید تکمیل شود به سرور ارسال میکند.
مثال دیگر از موارد مفید واقع شدن Poll زمانی است که مکان یک کاربر را روی نقشه ردگیری میکنیم. در یک نقشه مانند Uber میتوانیم نزدیک شدن راننده را به طور مکرر با Polling برای دیدن آخرین نتایج مورد مشاهده قرار دهیم. از آنجا که این دادهها به طور مکرر تغییر مییابند، باید یک بازه برای Poll کردن مکان تنظیم کنیم تا مطمئن شویم که همیشه دادهها بهروزی داریم.
پیادهسازی Polling
در این بخش یک تابع Poll ساده مینویسیم که از Promise-ها برای تشخیص نتایج واکشی استفاده میکند. کد آن به صورت زیر است:
1const poll = async ({ fn, validate, interval, maxAttempts }) => {
2 let attempts = 0;
3
4 const executePoll = async (resolve, reject) => {
5 const result = await fn();
6 attempts++;
7
8 if (validate(result)) {
9 return resolve(result);
10 } else if (maxAttempts && attempts === maxAttempts) {
11 return reject(new Error('Exceeded max attempts'));
12 } else {
13 setTimeout(executePoll, interval, resolve, reject);
14 }
15 };
16
17 return new Promise(executePoll);
18};
این تابع Poll یک «تابع مرتبه بالا» (higher-order function) است که یک تابع دیگر به نام executePoll بازگشت میدهد. تابع executePoll یک Promise بازگشت میدهد و به طور بازگشتی تا زمانی که شرطی محقق شود اجرا میشود. تابع Poll چهار متغیر به عنوان آرگومان میگیرد.
- Fn – این تابعی است که در طی یک بازه مفروض اجرا میشود. به طور معمول این یک درخواست API خواهد بود.
- Valid – این نیز یک تابع است که در آن یک تست تعریف میکنیم تا ببینیم آیا دادهها با آن چه میخواهیم تطبیق دارند یا نه. برای نمونه میتوانیم به سادگی تست کنیم آیا دادهها وجود دارند و یا میتوانیم بررسی کنیم آیا یک مشخصه تودرتو در پاسخ به حالت خاصی رسیده است یا نه.
به دو مثال زیر توجه کنید:
1validate = user =>!!user
2validate = checkout => checkout.status === 'COMPLETE'
- interval - این زمانی است که میخواهیم بین دو درخواست Poll منتظر بمانیم. این بازه به طور کامل بر مبنای کارکرد خاص در اپلیکیشن تعیین میشود و هر چه اهمیتِ داشتنِ اطلاعات بهروز بالا باشد، این بازه زمانی بین درخواستهای Poll نیز باید کوتاهتر باشد.
- maxAttempts – ما باید بتوانیم برخی کرانهای بالای معقول برای تعداد درخواستهای Poll تعیین کنیم تا از اجرای نامتناهی آنها جلوگیری کنیم.
تابع Poll ما با اعلان کردن یک متغیر attempts آغاز میشود که یک کلوژر پیرامون آن ایجاد میکنیم تا تعداد دفعاتی که API خود را Poll کردهایم ردگیری کنیم. سپس تابع excutePoll را اعلان میکنیم که یک Promise بازگشت میدهد. این تابع به ما امکان میدهد که به طور پیوسته executePoll را به طور بازگشتی فراخوانی کنیم و تنها زمانی که به مقدار معتبری برسیم resolve میشود.
تابع executePoll نیز به صورت async اعلان میشود، بنابراین میتوانیم تابع fn خود را به سادگی با استفاده از await اجرا کنیم. سپس در زمان بازگشت آن عدد attempts را یک واحد افزایش میدهیم. ما validate را روی result حاصل از fn فراخوانی میکنیم و اگر مقدار true بازگشت دهد، مقدار را با موفقیت resolve میکنیم. اگر نتیجه معتبر نباشد، بررسی میکنیم آیا به بیشینه تلاش poll رسیدهایم یا نه و در این حالت یک خطا صادر میکنیم. در غیر این صورت یک setTimeout برای interval مفروض تعیین کرده و سپس تابع را به صورت بازگشتی فراخوانی میکنیم تا دوباره poll کنیم.
مثال Polling
مثال زیر را میتوانید در یک فایل جاوا اسکریپت به طور لوکال چسبانده و با استفاده از node اجرا کنید. این مثال همان تابع Poll که در بخش قبلی ساختیم را میگیرد و آن را روی یک درخواست ساختگی API اعمال میکند. این مثال وضعیت انتظار برای ایجاد یک کاربر را شبیهسازی میکند که در این مورد 12 ثانیه طول میکشد. ما در هر ثانیه یک بار API را Poll میکنیم تا این که کاربری که ایجاد شده بازگشت یابد و تابع then زنجیرهسازیشده resolve شود.
1const poll = async ({ fn, validate, interval, maxAttempts }) => {
2 console.log('Start poll...');
3 let attempts = 0;
4
5 const executePoll = async (resolve, reject) => {
6 console.log('- poll');
7 const result = await fn();
8 attempts++;
9
10 if (validate(result)) {
11 return resolve(result);
12 } else if (maxAttempts && attempts === maxAttempts) {
13 return reject(new Error('Exceeded max attempts'));
14 } else {
15 setTimeout(executePoll, interval, resolve, reject);
16 }
17 };
18
19 return new Promise(executePoll);
20};
21
22const simulateServerRequestTime = interval => {
23 return new Promise(resolve => {
24 setTimeout(() => {
25 resolve();
26 }, interval);
27 });
28};
29
30const TIME_FOR_AUTH_PROVIDER = 10000;
31const TIME_TO_CREATE_NEW_USER = 2000;
32
33let fakeUser = null;
34const createUser = (() => {
35 setTimeout(() => {
36 fakeUser = {
37 id: '123',
38 username: 'testuser',
39 name: 'Test User',
40 createdAt: Date.now(),
41 };
42 }, TIME_FOR_AUTH_PROVIDER + TIME_TO_CREATE_NEW_USER);
43})();
44
45const mockApi = async () => {
46 await simulateServerRequestTime(500);
47 return fakeUser;
48};
49
50const validateUser = user => !!user;
51const POLL_INTERVAL = 1000;
52const pollForNewUser = poll({
53 fn: mockApi,
54 validate: validateUser,
55 interval: POLL_INTERVAL,
56})
57 .then(user => console.log(user))
58 .catch(err => console.error(err));
سخن پایانی
به این ترتیب به پایان این مقاله میرسیم. Polling یک تکنیک ساده اما قدرتمند است که به شما امکان میدهد به طور دورهای جدیدترین مقادیر دادهها را بررسی کرده و از ارائه درخواستهای اضافی تا زمانی که به حالت مطلوب نرسیده است جلوگیری کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای جاوا اسکریپت
- مجموعه آموزشهای برنامهنویسی
- آموزش JavaScript ES6 (جاوااسکریپت)
- تشخیص چهره در مرورگر با API جاوا اسکریپت — به زبان ساده
- شیء (Object) در جاوا اسکریپت — راهنمای کاربردی
==