راهنمای جامع استفاده از AbortController جاوااسکریپت برای لغو مؤثر درخواستها در توسعه وب مدرن. الگوهای عملی و بهترین شیوهها را بیاموزید.
JavaScript AbortController: تسلط بر الگوهای لغو درخواست
در توسعه وب مدرن، عملیات ناهمزمان امری رایج است. چه دریافت داده از یک سرور راه دور، چه آپلود فایلها یا انجام محاسبات پیچیده در پسزمینه، جاوااسکریپت به شدت به promiseها و توابع ناهمزمان متکی است. با این حال، عملیات ناهمزمان کنترلنشده میتواند منجر به مشکلات عملکردی، هدر رفتن منابع و رفتار غیرمنتظره شود. اینجاست که AbortController
به کار میآید. این مقاله راهنمای جامعی برای تسلط بر الگوهای لغو درخواست با استفاده از AbortController
جاوااسکریپت ارائه میدهد و شما را قادر میسازد تا برنامههای وب قویتر و کارآمدتری برای مخاطبان جهانی بسازید.
AbortController چیست؟
AbortController
یک API داخلی جاوااسکریپت است که به شما امکان میدهد یک یا چند درخواست وب را لغو کنید. این ابزار راهی برای ارسال سیگنال لغو یک عملیات فراهم میکند و از ترافیک شبکه و مصرف منابع غیرضروری جلوگیری میکند. AbortController
در کنار AbortSignal
کار میکند که به عملیات ناهمزمانی که قرار است لغو شود، ارسال میگردد. این دو با هم یک مکانیزم قدرتمند و انعطافپذیر برای مدیریت وظایف ناهمزمان ارائه میدهند.
چرا از AbortController استفاده کنیم؟
سناریوهای متعددی از استفاده AbortController
بهرهمند میشوند:
- بهبود عملکرد: لغو درخواستهای در حال انتقالی که دیگر مورد نیاز نیستند، ترافیک شبکه را کاهش داده و منابع را آزاد میکند، که منجر به برنامههای سریعتر و واکنشگراتر میشود.
- جلوگیری از شرایط رقابتی (Race Conditions): هنگامی که چندین درخواست به سرعت پشت سر هم آغاز میشوند، ممکن است فقط نتیجه آخرین درخواست مرتبط باشد. لغو درخواستهای قبلی از شرایط رقابتی جلوگیری کرده و یکپارچگی دادهها را تضمین میکند.
- بهبود تجربه کاربری: در سناریوهایی مانند جستجوی همزمان با تایپ یا بارگذاری محتوای پویا، لغو درخواستهای منسوخ شده تجربهی کاربری روانتر و واکنشگراتری را فراهم میکند.
- مدیریت منابع: دستگاههای تلفن همراه و محیطهای با منابع محدود از لغو درخواستهای طولانی یا غیرضروری برای صرفهجویی در عمر باتری و پهنای باند بهرهمند میشوند.
کاربرد پایه
در اینجا یک مثال پایه برای نشان دادن نحوه استفاده از AbortController
با fetch
API آورده شده است:
مثال ۱: لغو ساده Fetch
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});
// Abort the fetch request after 5 seconds
setTimeout(() => {
controller.abort();
}, 5000);
توضیح:
- یک
AbortController
جدید ایجاد میشود. - خاصیت
signal
ازAbortController
به گزینههایfetch
ارسال میشود. - یک تابع
setTimeout
برای لغو درخواست پس از ۵ ثانیه با فراخوانیcontroller.abort()
استفاده میشود. - بلوک
catch
خطایAbortError
را مدیریت میکند که هنگام لغو شدن درخواست پرتاب میشود.
الگوهای پیشرفته لغو درخواست
فراتر از مثال پایه، چندین الگوی پیشرفته وجود دارد که میتوان برای بهرهبرداری مؤثر از AbortController
از آنها استفاده کرد.
الگوی ۱: لغو هنگام Unmount شدن کامپوننت (مثال React)
در فریمورکهای مبتنی بر کامپوننت مانند React، معمول است که درخواستها هنگام mount شدن کامپوننت آغاز و هنگام unmount شدن آن لغو شوند. این کار از نشت حافظه (memory leaks) جلوگیری کرده و تضمین میکند که برنامه به پردازش داده برای کامپوننتهایی که دیگر قابل مشاهده نیستند، ادامه ندهد.
import React, { useState, useEffect } from 'react';
function DataComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
setError(error);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => {
controller.abort(); // Cleanup function to abort the request
};
}, []); // Empty dependency array ensures this runs only on mount/unmount
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
return (
Data:
{JSON.stringify(data, null, 2)}
);
}
export default DataComponent;
توضیح:
- هوک
useEffect
برای انجام عملیات جانبی (در این مورد، دریافت داده) هنگام mount شدن کامپوننت استفاده میشود. AbortController
درون هوکuseEffect
ایجاد میشود.- تابع پاکسازی (cleanup function) که توسط
useEffect
بازگردانده میشود، هنگام unmount شدن کامپوننتcontroller.abort()
را فراخوانی میکند و اطمینان میدهد که هر درخواست در حال انجام لغو میشود. - یک آرایه وابستگی خالی (
[]
) بهuseEffect
ارسال میشود که نشان میدهد این effect فقط یک بار هنگام mount و یک بار هنگام unmount اجرا شود.
الگوی ۲: Debouncing و Throttling
Debouncing و Throttling تکنیکهایی هستند که برای محدود کردن نرخ اجرای یک تابع استفاده میشوند. آنها معمولاً در سناریوهایی مانند جستجوی همزمان با تایپ یا تغییر اندازه پنجره، که رویدادهای مکرر میتوانند عملیات پرهزینهای را فعال کنند، به کار میروند. AbortController
میتواند در کنار debouncing و throttling برای لغو درخواستهای قبلی هنگام وقوع یک رویداد جدید استفاده شود.
مثال: جستجوی Debounced با AbortController
function debouncedSearch(query, delay = 300) {
let controller = null; // Keep the controller in the scope
return function() {
if (controller) {
controller.abort(); // Abort previous request
}
controller = new AbortController(); // Create a new AbortController
const signal = controller.signal;
return new Promise((resolve, reject) => {
setTimeout(() => {
fetch(`https://api.example.com/search?q=${query}`, { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
resolve(data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Search Aborted for: ' + query);
} else {
reject(error);
}
});
}, delay);
});
};
}
// Usage Example:
const search = debouncedSearch('Example Query');
search().then(results => console.log(results)).catch(error => console.error(error)); //Initial search
search().then(results => console.log(results)).catch(error => console.error(error)); //Another search; aborts the previous
search().then(results => console.log(results)).catch(error => console.error(error)); //...and another
توضیح:
- تابع
debouncedSearch
یک نسخه debounced از تابع جستجو را برمیگرداند. - هر بار که تابع debounced فراخوانی میشود، ابتدا هر درخواست قبلی را با استفاده از
controller.abort()
لغو میکند. - سپس یک
AbortController
جدید ایجاد شده و برای شروع یک درخواست جدید استفاده میشود. - تابع
setTimeout
تأخیری را قبل از ارسال درخواست ایجاد میکند و تضمین میکند که جستجو فقط پس از توقف تایپ کاربر برای مدت زمان مشخصی انجام شود.
الگوی ۳: ترکیب چندین AbortSignal
در برخی موارد، ممکن است نیاز داشته باشید یک درخواست را بر اساس چندین شرط لغو کنید. به عنوان مثال، ممکن است بخواهید یک درخواست را در صورت وقوع timeout یا اگر کاربر از صفحه خارج شود، لغو کنید. شما میتوانید با ترکیب چندین نمونه AbortSignal
در یک سیگنال واحد به این هدف دست یابید.
این الگو به طور مستقیم به صورت بومی پشتیبانی نمیشود و شما معمولاً باید منطق ترکیب خود را پیادهسازی کنید.
الگوی ۴: Timeoutها و مهلتها
تنظیم timeout برای درخواستها برای جلوگیری از معلق ماندن نامحدود آنها حیاتی است. AbortController
میتواند برای پیادهسازی آسان timeoutها استفاده شود.
async function fetchDataWithTimeout(url, timeout) {
const controller = new AbortController();
const signal = controller.signal;
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
try {
const response = await fetch(url, { signal });
clearTimeout(timeoutId); // Clear timeout if request completes successfully
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId); // Clear timeout in case of any error
throw error;
}
}
// Usage:
fetchDataWithTimeout('https://api.example.com/data', 3000) // 3 seconds timeout
.then(data => console.log(data))
.catch(error => console.error(error));
توضیح:
- تابع
fetchDataWithTimeout
یک URL و یک مقدار timeout را به عنوان آرگومان میگیرد. - یک تابع
setTimeout
برای لغو درخواست پس از timeout مشخص شده استفاده میشود. - تابع
clearTimeout
هم در بلوکtry
و هم در بلوکcatch
فراخوانی میشود تا اطمینان حاصل شود که در صورت تکمیل موفقیتآمیز درخواست یا بروز خطا، timeout پاک میشود.
ملاحظات جهانی و بهترین شیوهها
هنگام کار با AbortController
در یک زمینه جهانی، در نظر گرفتن موارد زیر ضروری است:
- بومیسازی: پیامهای خطا و عناصر رابط کاربری مربوط به لغو درخواست باید بومیسازی شوند تا برای کاربران در مناطق مختلف قابل دسترس باشند.
- شرایط شبکه: شرایط شبکه میتواند در مناطق جغرافیایی مختلف به طور قابل توجهی متفاوت باشد. مقادیر timeout و استراتژیهای لغو را بر اساس تأخیر و پهنای باند شبکه مورد انتظار در مناطق مختلف تنظیم کنید.
- ملاحظات سمت سرور: اطمینان حاصل کنید که APIهای سمت سرور شما درخواستهای لغو شده را به درستی مدیریت میکنند. به عنوان مثال، ممکن است بخواهید مکانیزمی برای متوقف کردن پردازش یک درخواست در صورتی که کلاینت آن را لغو کرده است، پیادهسازی کنید.
- دسترسیپذیری: بازخورد واضح و آموزندهای را هنگام لغو یک درخواست به کاربران ارائه دهید. این میتواند به کاربران کمک کند تا دلیل لغو درخواست را درک کرده و اقدام مناسب را انجام دهند.
- موبایل در مقابل دسکتاپ: کاربران موبایل ممکن است اتصالات ناپایدارتری داشته باشند، اطمینان حاصل کنید که timeoutها و مدیریت خطای شما برای دستگاههای موبایل قوی است.
- مرورگرهای مختلف: تست در مرورگرها و نسخههای مختلف را برای بررسی هرگونه مشکل سازگاری در مورد API AbortController در نظر بگیرید.
مدیریت خطا
مدیریت صحیح خطا هنگام استفاده از AbortController
بسیار مهم است. همیشه AbortError
را بررسی کرده و به طور مناسب آن را مدیریت کنید.
try {
// ... fetch code ...
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was aborted');
// Perform any necessary cleanup or UI updates
} else {
console.error('An error occurred:', error);
// Handle other errors
}
}
نتیجهگیری
AbortController
جاوااسکریپت ابزاری قدرتمند برای مدیریت عملیات ناهمزمان و بهبود عملکرد و واکنشگرایی برنامههای وب است. با درک کاربرد پایه و الگوهای پیشرفته، میتوانید برنامههای قویتر و کارآمدتری بسازید که تجربه کاربری بهتری را برای مخاطبان جهانی فراهم میکنند. به یاد داشته باشید که هنگام پیادهسازی لغو درخواست در برنامههای خود، بومیسازی، شرایط شبکه و ملاحظات سمت سرور را در نظر بگیرید.
با بهرهگیری از الگوهای ذکر شده در بالا، توسعهدهندگان میتوانند با اطمینان عملیات ناهمزمان را مدیریت کنند، استفاده از منابع را بهینه سازند و تجربیات کاربری استثنایی را در محیطهای متنوع و برای مخاطبان جهانی ارائه دهند.
این راهنمای جامع باید پایه محکمی برای تسلط بر الگوهای لغو درخواست با استفاده از AbortController
جاوااسکریپت فراهم کند. کدنویسی خوبی داشته باشید!