العربية

تعلم كيفية استخدام JavaScript AbortController لإلغاء العمليات غير المتزامنة بفعالية مثل طلبات الاسترجاع والمؤقتات والمزيد.

JavaScript AbortController: إتقان إلغاء العمليات غير المتزامنة

في تطوير الويب الحديث، العمليات غير المتزامنة منتشرة في كل مكان. غالبًا ما تتضمن جلب البيانات من واجهات برمجة التطبيقات، وتعيين المؤقتات، والتعامل مع تفاعلات المستخدمين التعليمات البرمجية التي تعمل بشكل مستقل وربما لفترة طويلة. ومع ذلك، هناك سيناريوهات تحتاج فيها إلى إلغاء هذه العمليات قبل اكتمالها. هذا هو المكان الذي تأتي فيه واجهة AbortController في JavaScript للإنقاذ. إنها توفر طريقة نظيفة وفعالة لإشارة طلبات الإلغاء إلى عمليات DOM والمهام غير المتزامنة الأخرى.

فهم الحاجة إلى الإلغاء

قبل الغوص في التفاصيل الفنية، دعنا نفهم سبب أهمية إلغاء العمليات غير المتزامنة. ضع في اعتبارك هذه السيناريوهات الشائعة:

تقديم AbortController و AbortSignal

تم تصميم واجهة AbortController لحل مشكلة إلغاء العمليات غير المتزامنة. وهي تتكون من مكونين رئيسيين:

الاستخدام الأساسي: إلغاء طلبات Fetch

لنبدأ بمثال بسيط لإلغاء طلب 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:', data);
  })
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Fetch aborted');
    } else {
      console.error('Fetch error:', error);
    }
  });

// To cancel the fetch request:
controller.abort();

شرح:

  1. نقوم بإنشاء مثيل AbortController.
  2. نحصل على AbortSignal المرتبط من controller.
  3. نقوم بتمرير signal إلى خيارات fetch.
  4. إذا احتجنا إلى إلغاء الطلب، فإننا نستدعي controller.abort().
  5. في كتلة .catch()، نتحقق مما إذا كان الخطأ هو AbortError. إذا كان الأمر كذلك، فإننا نعلم أن الطلب قد تم إلغاؤه.

التعامل مع AbortError

عند استدعاء controller.abort()، سيتم رفض طلب fetch باستخدام AbortError. من الضروري التعامل مع هذا الخطأ بشكل مناسب في التعليمات البرمجية الخاصة بك. قد يؤدي عدم القيام بذلك إلى رفض الوعود غير المعالجة والسلوك غير المتوقع.

إليك مثال أكثر قوة للتعامل مع الأخطاء:


const controller = new AbortController();
const signal = controller.signal;

async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data', { signal });
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    const data = await response.json();
    console.log('Data:', data);
    return data;
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('Fetch aborted');
      return null; // Or throw the error to be handled further up
    } else {
      console.error('Fetch error:', error);
      throw error; // Re-throw the error to be handled further up
    }
  }
}

fetchData();

// To cancel the fetch request:
controller.abort();

أفضل الممارسات للتعامل مع AbortError:

إلغاء المؤقتات باستخدام AbortSignal

يمكن أيضًا استخدام AbortSignal لإلغاء المؤقتات التي تم إنشاؤها باستخدام setTimeout أو setInterval. يتطلب هذا القليل من العمل اليدوي، حيث أن وظائف المؤقت المضمنة لا تدعم AbortSignal مباشرة. تحتاج إلى إنشاء دالة مخصصة تستمع إلى إشارة الإيقاف وتزيل المؤقت عند تشغيله.


function cancellableTimeout(callback, delay, signal) {
  let timeoutId;

  const timeoutPromise = new Promise((resolve, reject) => {
    timeoutId = setTimeout(() => {
      resolve(callback());
    }, delay);

    signal.addEventListener('abort', () => {
      clearTimeout(timeoutId);
      reject(new Error('Timeout Aborted'));
    });
  });

  return timeoutPromise;
}

const controller = new AbortController();
const signal = controller.signal;


cancellableTimeout(() => {
  console.log('Timeout executed');
}, 2000, signal)
.then(() => console.log("Timeout finished successfully"))
.catch(err => console.log(err));

// To cancel the timeout:
controller.abort();

شرح:

  1. تأخذ الدالة cancellableTimeout استدعاء، وتأخير، وAbortSignal كوسيطات.
  2. يُنشئ setTimeout ويخزن معرف المهلة.
  3. يضيف مستمع حدث إلى AbortSignal الذي يستمع إلى حدث abort.
  4. عند تشغيل حدث abort، يزيل مستمع الحدث المهلة ويرفض الوعد.

إلغاء مستمعي الأحداث

على غرار المؤقتات، يمكنك استخدام AbortSignal لإلغاء مستمعي الأحداث. هذا مفيد بشكل خاص عندما تريد إزالة مستمعي الأحداث المرتبطين بمكون يتم إلغاء تحميله.


const controller = new AbortController();
const signal = controller.signal;

const button = document.getElementById('myButton');

button.addEventListener('click', () => {
  console.log('Button clicked!');
}, { signal });

// To cancel the event listener:
controller.abort();

شرح:

  1. نقوم بتمرير signal كخيار إلى طريقة addEventListener.
  2. عندما يتم استدعاء controller.abort()، سيتمت إزالة مستمع الحدث تلقائيًا.

AbortController في مكونات React

في React، يمكنك استخدام AbortController لإلغاء العمليات غير المتزامنة عندما يتم إلغاء تحميل مكون. هذا ضروري لمنع تسرب الذاكرة والأخطاء الناتجة عن تحديث المكونات التي تم إلغاء تحميلها. إليك مثال باستخدام الخطاف useEffect:


import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    async function fetchData() {
      try {
        const response = await fetch('https://api.example.com/data', { signal });
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        const data = await response.json();
        setData(data);
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          console.error('Fetch error:', error);
        }
      }
    }

    fetchData();

    return () => {
      controller.abort(); // Cancel the fetch request when the component unmounts
    };
  }, []); // Empty dependency array ensures this effect runs only once on mount

  return (
    
{data ? (

Data: {JSON.stringify(data)}

) : (

Loading...

)}
); } export default MyComponent;

شرح:

  1. نقوم بإنشاء AbortController داخل الخطاف useEffect.
  2. نقوم بتمرير signal إلى طلب fetch.
  3. نقوم بإرجاع دالة تنظيف من الخطاف useEffect. سيتم استدعاء هذه الدالة عندما يتم إلغاء تحميل المكون.
  4. داخل دالة التنظيف، نستدعي controller.abort() لإلغاء طلب الاسترجاع.

حالات الاستخدام المتقدمة

ربط إشارات الإلغاء

في بعض الأحيان، قد ترغب في ربط إشارات AbortSignal المتعددة معًا. على سبيل المثال، قد يكون لديك مكون رئيسي يحتاج إلى إلغاء العمليات في مكوناته الفرعية. يمكنك تحقيق ذلك عن طريق إنشاء AbortController جديد وتمرير إشارته إلى كل من المكونات الأصل والفرعية.

استخدام AbortController مع مكتبات الجهات الخارجية

إذا كنت تستخدم مكتبة تابعة لجهة خارجية لا تدعم AbortSignal مباشرة، فقد تحتاج إلى تكييف التعليمات البرمجية الخاصة بك للعمل مع آلية الإلغاء الخاصة بالمكتبة. قد يتضمن ذلك تجميع وظائف المكتبة غير المتزامنة في وظائفك الخاصة التي تتعامل مع AbortSignal.

فوائد استخدام AbortController

توافق المتصفح

يحظى AbortController بدعم واسع النطاق في المتصفحات الحديثة، بما في ذلك Chrome و Firefox و Safari و Edge. يمكنك التحقق من جدول التوافق على MDN Web Docs للحصول على أحدث المعلومات.

ملء التعليمات البرمجية

بالنسبة للمتصفحات القديمة التي لا تدعم AbortController بشكل أصلي، يمكنك استخدام ملء التعليمات البرمجية. ملء التعليمات البرمجية هو جزء من التعليمات البرمجية التي توفر وظائف ميزة أحدث في المتصفحات القديمة. هناك العديد من ملء التعليمات البرمجية AbortController المتاحة عبر الإنترنت.

الخلاصة

واجهة AbortController هي أداة قوية لإدارة العمليات غير المتزامنة في JavaScript. باستخدام AbortController، يمكنك كتابة تعليمات برمجية أنظف وأكثر أداءً وأكثر قوة تتعامل مع الإلغاء بأناقة. سواء كنت تجلب بيانات من واجهات برمجة التطبيقات، أو تقوم بتعيين المؤقتات، أو تدير مستمعي الأحداث، يمكن أن يساعدك AbortController في تحسين الجودة العامة لتطبيقات الويب الخاصة بك.

القراءة الإضافية