راهنمای جامع AbortController API در جاوا اسکریپت، شامل لغو درخواست، مدیریت منابع، مدیریت خطا و موارد استفاده پیشرفته برای توسعه وب مدرن.
AbortController API: تسلط بر لغو درخواست و مدیریت منابع
در توسعه وب مدرن، مدیریت کارآمد عملیات ناهمزمان برای ساخت برنامههای پاسخگو و با کارایی بالا حیاتی است. AbortController API مکانیزم قدرتمندی برای لغو درخواستها و مدیریت منابع فراهم میکند و تجربه کاربری بهتری را تضمین کرده و از سربار غیرضروری جلوگیری میکند. این راهنمای جامع، AbortController API را به تفصیل بررسی میکند و مفاهیم اصلی، موارد استفاده عملی و تکنیکهای پیشرفته آن را پوشش میدهد.
AbortController API چیست؟
AbortController API یک API داخلی جاوا اسکریپت است که به شما امکان میدهد یک یا چند درخواست وب را لغو کنید. این API از دو جزء اصلی تشکیل شده است:
- AbortController: شیء کنترلکنندهای که فرآیند لغو را آغاز میکند.
- AbortSignal: یک شیء سیگنال مرتبط با AbortController که به عملیات ناهمزمان (مثلاً یک درخواست
fetch
) ارسال میشود تا به سیگنالهای لغو گوش دهد.
هنگامی که متد abort()
روی AbortController فراخوانی میشود، AbortSignal مرتبط یک رویداد abort
را منتشر میکند که عملیات ناهمزمان میتواند به آن گوش داده و بر اساس آن پاسخ دهد. این امکان لغو روان درخواستها را فراهم میکند و از انتقال و پردازش دادههای غیرضروری جلوگیری میکند.
مفاهیم اصلی
۱. ایجاد یک AbortController
برای استفاده از AbortController API، ابتدا باید یک نمونه از کلاس AbortController
ایجاد کنید:
const controller = new AbortController();
۲. دریافت AbortSignal
نمونه AbortController
از طریق خاصیت signal
خود به یک شیء AbortSignal
دسترسی میدهد:
const signal = controller.signal;
۳. ارسال AbortSignal به یک عملیات ناهمزمان
سپس AbortSignal
به عنوان یک گزینه به عملیات ناهمزمانی که میخواهید کنترل کنید، ارسال میشود. به عنوان مثال، هنگام استفاده از fetch
API، میتوانید signal
را به عنوان بخشی از شیء گزینهها ارسال کنید:
fetch('/api/data', { signal })
.then(response => response.json())
.then(data => {
console.log('داده دریافت شد:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('درخواست fetch لغو شد');
} else {
console.error('خطای fetch:', error);
}
});
۴. لغو کردن درخواست
برای لغو درخواست، متد abort()
را روی نمونه AbortController
فراخوانی کنید:
controller.abort();
این کار رویداد abort
را روی AbortSignal
مرتبط فعال میکند و باعث میشود درخواست fetch
با یک AbortError
رد (reject) شود.
موارد استفاده عملی
۱. لغو کردن درخواستهای Fetch
یکی از رایجترین موارد استفاده از AbortController API، لغو درخواستهای fetch
است. این امر به ویژه در سناریوهایی مفید است که کاربر از یک صفحه خارج میشود یا عملی را انجام میدهد که درخواست در حال انجام را غیرضروری میکند. سناریویی را در نظر بگیرید که کاربر در یک وبسایت تجارت الکترونیک به دنبال محصولات میگردد. اگر کاربر قبل از تکمیل درخواست جستجوی قبلی، یک عبارت جستجوی جدید تایپ کند، میتوان از AbortController برای لغو درخواست قبلی استفاده کرد و در پهنای باند و قدرت پردازش صرفهجویی کرد.
let controller = null;
function searchProducts(query) {
if (controller) {
controller.abort();
}
controller = new AbortController();
const signal = controller.signal;
fetch(`/api/products?q=${query}`, { signal })
.then(response => response.json())
.then(products => {
displayProducts(products);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('جستجو لغو شد');
} else {
console.error('خطای جستجو:', error);
}
});
}
function displayProducts(products) {
// نمایش محصولات در رابط کاربری
console.log('محصولات:', products);
}
// مثال استفاده:
searchProducts('shoes');
searchProducts('shirts'); // جستجوی قبلی برای 'shoes' را لغو میکند
۲. پیادهسازی زمان وقفه (Timeout)
از AbortController API میتوان برای پیادهسازی زمان وقفه (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);
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('درخواست به دلیل وقفه زمانی لغو شد');
} else {
throw error;
}
}
}
// مثال استفاده:
fetchDataWithTimeout('/api/data', 5000) // وقفه زمانی ۵ ثانیهای
.then(data => {
console.log('داده دریافت شد:', data);
})
.catch(error => {
console.error('خطا:', error.message);
});
۳. مدیریت چندین عملیات ناهمزمان
از AbortController API میتوان برای مدیریت همزمان چندین عملیات ناهمزمان استفاده کرد. این قابلیت در سناریوهایی که نیاز به لغو گروهی از درخواستهای مرتبط دارید، مفید است. به عنوان مثال، یک برنامه داشبورد را تصور کنید که دادهها را از چندین منبع دریافت میکند. اگر کاربر از داشبورد خارج شود، تمام درخواستهای در حال انتظار باید برای آزاد کردن منابع لغو شوند.
const controller = new AbortController();
const signal = controller.signal;
const urls = [
'/api/data1',
'/api/data2',
'/api/data3'
];
async function fetchData(url) {
try {
const response = await fetch(url, { signal });
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log(`درخواست fetch برای ${url} لغو شد`);
} else {
console.error(`خطای fetch برای ${url}:`, error);
}
throw error;
}
}
Promise.all(urls.map(fetchData))
.then(results => {
console.log('تمام دادهها دریافت شد:', results);
})
.catch(error => {
console.error('خطا در دریافت دادهها:', error);
});
// برای لغو تمام درخواستها:
controller.abort();
تکنیکهای پیشرفته
۱. استفاده از AbortController با Event Listeners
از AbortController API میتوان برای مدیریت event listener ها نیز استفاده کرد. این کار برای پاکسازی event listener ها زمانی که یک کامپوننت از بین میرود یا یک رویداد خاص رخ میدهد، مفید است. به عنوان مثال، هنگام ساخت یک پخشکننده ویدیوی سفارشی، ممکن است بخواهید event listener هایی برای رویدادهای 'play'، 'pause' و 'ended' اضافه کنید. استفاده از AbortController تضمین میکند که این listener ها زمانی که دیگر به پخشکننده نیازی نیست، به درستی حذف میشوند و از نشت حافظه (memory leak) جلوگیری میکند.
function addEventListenerWithAbort(element, eventType, listener, signal) {
element.addEventListener(eventType, listener);
signal.addEventListener('abort', () => {
element.removeEventListener(eventType, listener);
});
}
// مثال استفاده:
const controller = new AbortController();
const signal = controller.signal;
const button = document.getElementById('myButton');
function handleClick() {
console.log('دکمه کلیک شد!');
}
addEventListenerWithAbort(button, 'click', handleClick, signal);
// برای حذف event listener:
controller.abort();
۲. زنجیرهسازی AbortSignal ها
در برخی موارد، ممکن است نیاز به زنجیرهسازی چندین AbortSignal با یکدیگر داشته باشید. این کار به شما امکان میدهد سلسله مراتبی از سیگنالهای لغو ایجاد کنید، که در آن لغو یک سیگنال به طور خودکار تمام فرزندان آن را لغو میکند. این کار را میتوان با ایجاد یک تابع کمکی که چندین سیگنال را در یک سیگنال واحد ترکیب میکند، انجام داد. یک جریان کاری پیچیده را تصور کنید که در آن چندین کامپوننت به یکدیگر وابسته هستند. اگر یک کامپوننت با شکست مواجه شود یا لغو شود، ممکن است بخواهید تمام کامپوننتهای وابسته را به طور خودکار لغو کنید.
function combineAbortSignals(...signals) {
const controller = new AbortController();
signals.forEach(signal => {
if (signal) {
signal.addEventListener('abort', () => {
controller.abort();
});
}
});
return controller.signal;
}
// مثال استفاده:
const controller1 = new AbortController();
const controller2 = new AbortController();
const combinedSignal = combineAbortSignals(controller1.signal, controller2.signal);
fetch('/api/data', { signal: combinedSignal })
.then(response => response.json())
.then(data => {
console.log('داده دریافت شد:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('درخواست fetch لغو شد');
} else {
console.error('خطای fetch:', error);
}
});
// لغو کردن controller1 درخواست fetch را نیز لغو خواهد کرد:
controller1.abort();
۳. مدیریت سراسری AbortError ها
برای بهبود قابلیت نگهداری کد، میتوانید یک مدیریتکننده خطای سراسری برای گرفتن و مدیریت استثناهای AbortError
ایجاد کنید. این کار میتواند مدیریت خطا را در برنامه شما ساده کرده و رفتار ثابتی را تضمین کند. این کار را میتوان با ایجاد یک تابع مدیریت خطای سفارشی که AbortError ها را بررسی کرده و اقدام مناسب را انجام میدهد، انجام داد. این رویکرد متمرکز، بهروزرسانی منطق مدیریت خطا را آسانتر کرده و ثبات را در سراسر برنامه تضمین میکند.
function handleAbortError(error) {
if (error.name === 'AbortError') {
console.log('درخواست به صورت سراسری لغو شد');
// هرگونه پاکسازی یا بهروزرسانی UI لازم را انجام دهید
}
}
// مثال استفاده:
fetch('/api/data')
.then(response => response.json())
.then(data => {
console.log('داده دریافت شد:', data);
})
.catch(error => {
handleAbortError(error);
console.error('خطای fetch:', error);
});
مدیریت خطا
هنگامی که یک درخواست با استفاده از AbortController API لغو میشود، promise مربوط به fetch
با یک AbortError
رد (reject) میشود. مهم است که این خطا را به درستی مدیریت کنید تا از رفتار غیرمنتظره در برنامه خود جلوگیری کنید.
fetch('/api/data', { signal })
.then(response => response.json())
.then(data => {
console.log('داده دریافت شد:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('درخواست fetch لغو شد');
// هرگونه پاکسازی یا بهروزرسانی UI لازم را انجام دهید
} else {
console.error('خطای fetch:', error);
// سایر خطاها را مدیریت کنید
}
});
در بلوک مدیریت خطا، میتوانید با بررسی خاصیت error.name
، وجود AbortError
را بررسی کنید. اگر خطا از نوع AbortError
باشد، میتوانید هرگونه پاکسازی یا بهروزرسانی UI لازم را انجام دهید، مانند نمایش یک پیام به کاربر یا بازنشانی وضعیت برنامه.
بهترین شیوهها
- همیشه استثناهای
AbortError
را مدیریت کنید: اطمینان حاصل کنید که کد شما به درستی استثناهایAbortError
را مدیریت میکند تا از رفتار غیرمنتظره جلوگیری شود. - از پیامهای خطای توصیفی استفاده کنید: پیامهای خطای واضح و آموزنده ارائه دهید تا به توسعهدهندگان در اشکالزدایی و رفع مشکلات کمک کند.
- منابع را پاکسازی کنید: هنگامی که یک درخواست لغو میشود، هرگونه منابع مرتبط مانند تایمرها یا event listener ها را پاکسازی کنید تا از نشت حافظه جلوگیری شود.
- مقادیر زمان وقفه را در نظر بگیرید: مقادیر زمان وقفه مناسبی را برای عملیات ناهمزمان تنظیم کنید تا از معلق ماندن نامحدود درخواستها جلوگیری شود.
- از AbortController برای عملیات طولانیمدت استفاده کنید: برای عملیاتی که ممکن است تکمیل آنها زمان زیادی طول بکشد، از AbortController API استفاده کنید تا به کاربران اجازه دهید در صورت نیاز عملیات را لغو کنند.
سازگاری با مرورگرها
AbortController API به طور گسترده در مرورگرهای مدرن، از جمله Chrome، Firefox، Safari و Edge پشتیبانی میشود. با این حال، مرورگرهای قدیمیتر ممکن است از این API پشتیبانی نکنند. برای اطمینان از سازگاری با مرورگرهای قدیمیتر، میتوانید از یک polyfill استفاده کنید. چندین polyfill در دسترس هستند که عملکرد AbortController را برای مرورگرهای قدیمیتر فراهم میکنند. این polyfill ها را میتوان به راحتی با استفاده از مدیر بستههایی مانند npm یا yarn در پروژه خود ادغام کرد.
آینده AbortController
AbortController API یک فناوری در حال تکامل است و نسخههای آینده این مشخصات ممکن است ویژگیها و بهبودهای جدیدی را معرفی کنند. بهروز ماندن با آخرین تحولات در AbortController API برای ساخت برنامههای وب مدرن و کارآمد بسیار مهم است. بهروزرسانیهای مرورگر و استانداردهای جاوا اسکریپت را دنبال کنید تا از قابلیتهای جدید به محض در دسترس قرار گرفتن، بهرهمند شوید.
نتیجهگیری
AbortController API ابزاری ارزشمند برای مدیریت عملیات ناهمزمان در جاوا اسکریپت است. با فراهم کردن مکانیزمی برای لغو درخواستها و مدیریت منابع، این API به توسعهدهندگان امکان میدهد تا برنامههای وب پاسخگوتر، کارآمدتر و کاربرپسندتری بسازند. درک مفاهیم اصلی، موارد استفاده عملی و تکنیکهای پیشرفته AbortController API برای توسعه وب مدرن ضروری است. با تسلط بر این API، توسعهدهندگان میتوانند برنامههای قوی و کارآمدی ایجاد کنند که تجربه کاربری بهتری را ارائه میدهند.