Toy API کالز کو JavaScript کے ساتھ پروڈکشن کے لیے تیار نیٹ ورکنگ میں کیسے تبدیل کیا جائے۔

اس منظر نامے کا تصور کریں۔ ہم صبح کے وقت خصوصیات بھیجتے ہیں۔ دوپہر میں، صارف بٹن پر کلک کرتا ہے اور UI بکواس دکھانا شروع کر دیتا ہے: غلط نتائج، گمشدہ اپ ڈیٹس، بے ترتیب غلطیاں جنہیں درخواست پر دوبارہ پیش نہیں کیا جا سکتا۔

کھلونوں کے درمیان یہی فاصلہ ہے۔ fetch() ٹکڑوں اور پروڈکشن نیٹ ورکنگ۔

اس گائیڈ میں، آپ اس خلا کو ختم کرنے کا طریقہ سیکھیں گے۔ ہم سادہ درخواستوں کے ساتھ شروعات کریں گے اور بتدریج اصلی ایپس کے لیے درکار پیٹرن شامل کریں گے، جیسے آرڈرنگ کنٹرول، ناکامی سے نمٹنے، دوبارہ کوششیں، اور منسوخی۔ بعد میں، ہم اپنے استعمال کے معاملے کے لیے صحیح ٹول کا انتخاب کرنے میں آپ کی مدد کرنے کے لیے ریٹ کو محدود کرنے، سرکٹ بریکرز، انضمام کی درخواست، اور کیشنگ جیسے مزید جدید موضوعات کا احاطہ کریں گے۔

جس کا ہم احاطہ کریں گے۔

شرطیں

آپ کو ماہر بننے کی ضرورت نہیں ہے، لیکن آپ کو پہلے سے ہی درج ذیل جاننا چاہیے:

  • کور جاوا اسکرپٹ اور async/await

  • براؤزر کا ڈیفالٹ DOM اپ ڈیٹ کریں۔

  • npm اسکرپٹ کا استعمال کرتے ہوئے Node.js پروجیکٹ کو کیسے چلایا جائے۔

  • براؤزر DevTools میں درخواستوں کا معائنہ کیسے کریں۔

اس ذخیرہ کی خصوصیات

اس مضمون کا ساتھی کوڈ GitHub repository js-fetch-production-demo میں دستیاب ہے۔ اس میں ایک چھوٹا ایکسپریس بیک اینڈ اور ایک چھوٹا ونیلا جاوا اسکرپٹ فرنٹ اینڈ شامل ہے۔

ایپ ٹکٹوں کی قطار میں لگنے والے نظام کی تقلید کرتی ہے جہاں بیک اینڈ کی ہر درخواست کو دی گئی قطار ID کے لیے اگلا ٹکٹ نمبر تفویض کیا جاتا ہے۔ ہر درخواست ہر قطار ID کے لیے ایک کاؤنٹر کو بڑھاتی ہے، اور فرنٹ اینڈ ہر واپسی ٹکٹ نمبر کو DOM میں شامل کرتا ہے۔

پسدید بے نقاب ہے۔ /tickets/:id/nextNumberہر درخواست اگلا نمبر واپس کرنے سے پہلے اس ٹکٹ ID کے کاؤنٹر میں اضافہ کرتی ہے۔

فرنٹ اینڈ آپ کو ٹکٹ کی ID منتخب کرنے، درخواست بھیجنے، اور واپس کیے گئے ہر نمبر کو اپنے صفحہ میں شامل کرنے کی اجازت دیتا ہے تاکہ آپ واضح طور پر دیکھ سکیں کہ وقت کے ساتھ جوابات کیسے آتے ہیں۔

جیسا کہ مضمون ہر سطح پر آگے بڑھتا ہے، ہم حقیقی دنیا کے نیٹ ورکنگ پیٹرن کے لیے چیلنجز اور حل دکھانے کے لیے اسی ایپ پر توسیع کریں گے۔

تنصیب کا طریقہ

پروجیکٹ روٹ میں درج ذیل کمانڈ کا استعمال کرتے ہوئے ہر چیز کو انسٹال کریں:

npm run install:all

کیسے چلائیں

پروجیکٹ روٹ سے دونوں سرورز شروع کریں۔

npm run dev

پھر اپنے براؤزر میں http://localhost:5173 کھولیں۔

بنیادی fetch

آئیے سب سے آسان مثال کے ساتھ شروع کریں۔ ایک بار بٹن پر کلک کرنے سے ایک درخواست ہوتی ہے اور UI واپس کیے گئے ٹکٹ نمبر کو شامل کرتا ہے۔

ڈیمو پسدید کو بے نقاب کرتا ہے۔ GET /tickets/:id/nextNumber. ہر درخواست اس ٹکٹ ID کے کاؤنٹر میں اضافہ کرتی ہے اور نئی قیمت واپس کرتی ہے۔

ایک درخواست کے بہاؤ کے لیے، درج ذیل بنیادی درآمدی پیٹرن کافی ہے:

const res = await fetch("/tickets/1/nextNumber");
const ticket = await res.json();
document.querySelector(".tickets").append(ticket.ticketNumber);

سست نیٹ ورک پروسیسنگ اور غلط جوابات سے گریز کریں۔

اس سطح پر سب کچھ درست نظر آتا ہے۔ لیکن نیٹ ورک ہمیشہ اس طرح کی پیش گوئی کے قابل نہیں ہوتے ہیں۔ سب سے پہلے، رفتار مختلف ہو سکتی ہے. کچھ درخواستوں میں دوسروں سے زیادہ وقت لگ سکتا ہے۔ اس کی تقلید کرنے کے لیے، آئیے بیک اینڈ میں بے ترتیب تاخیر شامل کریں۔

// /backend/index.js
app.get('/tickets/:id/nextNumber', (req, res) => {
  const ticketId = req.params.id;

  // Initialize counter if it doesn't exist
  if (!counters[ticketId]) {
    counters[ticketId] = 0;
  }

  counters[ticketId]++;
  const assignedNumber = counters[ticketId];

  // Delay the response to simulate slow network
  const delay = Math.floor(Math.random() * 5000);
  setTimeout(() => {
    res.json({
      ticketId: ticketId,
      ticketNumber: assignedNumber
    });
  }, delay);
});

آپ جو فوری طور پر محسوس کریں گے وہ یہ ہے کہ سست درخواستیں UI کو غیر جوابدہ محسوس کر سکتی ہیں، اس لیے لوڈ انڈیکیٹر مددگار ثابت ہو سکتا ہے۔ تاہم، یہ UI سطح کی بہتری ہے، نیٹ ورکنگ پیٹرن نہیں۔

ایک اور، زیادہ اہم مسئلہ یہ ہے کہ اگر کوئی صارف متعدد بار تیزی سے کلک کرتا ہے، تو جوابات ترتیب سے باہر ہو سکتے ہیں۔

UI سے غلط جواب

یہ پیداواری ماحول میں ناقابل قبول ہے۔ تو ہم یہ کیسے یقینی بناتے ہیں کہ UI ٹکٹ نمبروں کی صحیح ترتیب کو ظاہر کرتا ہے چاہے جوابات مختلف ترتیب میں آئیں؟

استعمال کا معاملہ آسان ہے۔ چونکہ فوری کلک کرنا صارف کے ارادے کے مطابق نہیں ہوسکتا ہے، اس لیے آپ بٹن کو اس وقت تک غیر فعال کر سکتے ہیں جب تک کہ پہلی درخواست مکمل نہ ہو جائے (دوسری UI سطح کی بہتری)۔

لیکن ہم مزید کر سکتے ہیں: جب نئی درخواستیں ہوں تو زیر التواء درخواستوں کو منسوخ کریں۔. یہ جگہ AbortController یہ وہ جگہ ہے جہاں API آتا ہے۔ AbortController ہر درخواست کے لیے مثالیں اور کالز abort() جب کوئی نئی درخواست شروع کی جاتی ہے، تو ہم اس کے بارے میں معلومات فراہم کرتے ہیں۔ یہ صرف حالیہ درخواست کو چالو کرے گا اور تمام پرانی درخواستوں کو منسوخ کر دے گا۔

UI میں بہتری اور منسوخی کی خصوصیات کے ساتھ، اب آپ غلط جوابات کی فکر کیے بغیر فوری کلکس کو سنبھال سکتے ہیں۔ فرنٹ اینڈ کوڈ:

// frontend/main.js
const ticketIdInput = document.getElementById('ticketId');
const fetchBtn = document.getElementById('fetchBtn');
const ticketList = document.getElementById('ticketList');
const loading = document.getElementById('loading');

let currentController = null;

function setLoadingState(isLoading) {
  fetchBtn.disabled = isLoading;
  loading.classList.toggle('hidden', !isLoading);
}

fetchBtn.addEventListener('click', async () => {
  const ticketId = ticketIdInput.value.trim();
  
  if (!ticketId) {
    alert('Please enter a ticket ID');
    return;
  }

  // Abort any in-flight request for this queue before starting a new one
  if (currentController) {
    currentController.abort();
  }
  currentController = new AbortController();
  setLoadingState(true);

  try {
    const res = await fetch(`/tickets/${ticketId}/nextNumber`, { signal: currentController.signal });
    const data = await res.json();
    
    // Append to DOM
    const ticketElement = document.createElement('div');
    ticketElement.className="ticket-item";
    ticketElement.textContent = `Queue \({data.ticketId}: #\){data.ticketNumber}`;
    ticketList.appendChild(ticketElement);
    
    // Scroll to latest item
    ticketElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
  } catch (error) {
    if (error.name === 'AbortError') return;
    console.error('Error fetching ticket:', error);
    alert('Error fetching ticket');
  } finally {
    setLoadingState(false);
  }
});

کوڈ یہاں موجود ہے: 01-abortController آپ ریپوزٹری میں برانچ پر جا کر مکمل عمل درآمد دیکھ سکتے ہیں۔

git checkout 01-abortController

HTTP غلطیوں اور ناقابل اعتماد جوابات کو ہینڈل کرنا

نیٹ ورک دوسرے طریقوں سے بھی غیر متوقع ہیں۔ اگر نیٹ ورک کی خرابی کی وجہ سے درخواست ناکام ہو جاتی ہے یا سرور 500 غلطی واپس کر دیتا ہے تو کیا ہوتا ہے؟ کہ fetch() چونکہ API HTTP کی غلطیاں نہیں پھینکتا ہے، اس لیے آپ کو ردعمل کی حیثیت کو چیک کرنے اور اس کے مطابق ہینڈل کرنے کی ضرورت ہے۔

آئیے اپنے پسدید میں بے ترتیب ناکامیوں کو شامل کریں۔

app.get('/tickets/:id/nextNumber', (req, res) => {
  const ticketId = req.params.id;

  // Initialize counter if it doesn't exist
  if (!counters[ticketId]) {
    counters[ticketId] = 0;
  }

  counters[ticketId]++;
  const assignedNumber = counters[ticketId];
  const shouldFail = Math.random() < 0.3; // 30% chance to fail with a 500 error

  const delay = Math.floor(Math.random() * 5000);
  setTimeout(() => {
    if (shouldFail) {
      res.status(500).json({
        error: 'Random backend failure',
        ticketId: ticketId
      });
      return;
    }

    res.json({
      ticketId: ticketId,
      ticketNumber: assignedNumber
    });
  }, delay);
});

جب آپ ایپ چلاتے ہیں تو آپ کو کچھ اس طرح نظر آئے گا:

UI میں بے ترتیب غلطیاں

کیا عجیب بات ہے کہ میں نے مندرجہ ذیل کو فرنٹ اینڈ میں رکھا ہے۔ fetch() کو try/catch چونکہ یہ بلاک ہوجاتا ہے، میں توقع کرتا ہوں کہ کوئی خرابی واقع ہوگی۔ لیکن fetch() صرف اس وقت ہوتا ہے جب HTTP کی خرابی کے بجائے نیٹ ورک کی خرابی ہوتی ہے۔. لہذا اگر سرور 500 غلطی واپس کرتا ہے، fetch() یہ کامیابی کے ساتھ حل ہو جائے گا، آپ کو جواب کی حیثیت کو چیک کرنا چاہیے کہ آیا یہ کوئی غلطی ہے۔

اس کو سنبھالنے کے لیے آپ چیک کر سکتے ہیں: res.ok درآمد کال کے بعد:

try {
  const res = await fetch(`/tickets/${ticketId}/nextNumber`, { signal: currentController.signal });
  
  if (!res.ok) {
    throw new Error(`HTTP error! status: ${res.status}`);
  }

  const data = await res.json();
  
  // Append to DOM
  const ticketElement = document.createElement('div');
  ticketElement.className="ticket-item";
  ticketElement.textContent = `Queue \({data.ticketId}: #\){data.ticketNumber}`;
  ticketList.appendChild(ticketElement);
  
  // Scroll to latest item
  ticketElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
} catch (error) {
  if (error.name === 'AbortError') return;
  console.error('Error fetching ticket:', error);
  alert('Error fetching ticket');
} finally {
  setLoadingState(false);
}

یہ نیٹ ورک کی غلطیوں اور HTTP کی خرابیوں کو پکڑ لے گا۔ مزید برآں، یہاں تک کہ اگر بیک اینڈ 500 کی خرابی پھینکتا ہے، تب بھی یہ کاؤنٹر کو اپ ڈیٹ کرتا ہے، لہذا اگلی کامیاب درخواست ایک اضافہ شدہ ٹکٹ نمبر واپس کر دے گی۔

گزارش ہے ۔ بے حسیاس کا مطلب ہے کہ بار بار درخواستوں کے مختلف اثرات ہو سکتے ہیں۔ ایک API کو ڈیزائن کرتے وقت، اس بات پر غور کرنا ضروری ہے کہ آیا اختتامی نقطوں کو غیرمعمولی ہونا چاہیے اور یہ کس طرح غلطی سے نمٹنے اور کلائنٹ کی جانب سے دوبارہ کوششوں کو متاثر کرتا ہے۔

خرابی سے نمٹنے کا کوڈ ہے۔ 02-errorHandling آپ ریپوزٹری میں برانچ پر جا کر مکمل عمل درآمد دیکھ سکتے ہیں۔

git checkout 02-errorHandling

عارضی غلطیوں کے لیے خودکار دوبارہ کوشش شامل کی گئی۔

اس مقام پر ہم نے خام کا استعمال کرتے ہوئے بنیادی غلطی سے نمٹنے اور منسوخی کو نافذ کیا ہے۔ fetch(). تاہم، فی الحال، اگر کوئی درخواست ناکام ہوجاتی ہے، تو صارف کو دوبارہ کوشش کرنے کے لیے دستی طور پر دوبارہ بٹن پر کلک کرنا ہوگا۔ تاہم، کچھ غلطیاں عارضی ہیں اور آپ کی درخواست پر دوبارہ کوشش کر کے اسے حل کیا جا سکتا ہے۔

دوبارہ کوشش کرنے کے طریقہ کار کو لاگو کرنے کا مطلب یہ ہے کہ ہار ماننے سے پہلے ایک ناکام درخواست کو ایک خاص تعداد میں خود بخود دوبارہ کوشش کرنا۔ یہ ایک سادہ لوپ اور دوبارہ کوششوں کے درمیان تھوڑی تاخیر کے ساتھ پورا کیا جا سکتا ہے، لیکن دوبارہ کوشش کرنے کی حکمت عملی زیادہ پیچیدہ ہو سکتی ہے۔

مثال کے طور پر، مختصر وقت میں بہت زیادہ درخواستوں کے ساتھ اپنے سرور کو اوور لوڈ کرنے سے بچنے کے لیے، آپ ممکنہ بیک آف کو لاگو کرنا چاہیں گے، جہاں ہر کوشش کے ساتھ دوبارہ کوششوں کے درمیان تاخیر تیزی سے بڑھ جاتی ہے۔ دوبارہ کوشش کرنے کی منطق کو ان غلطیوں کو بھی مدنظر رکھنا چاہیے جو دوبارہ کوشش کرنے کے قابل ہیں (جیسے نیٹ ورک کی خرابیاں، 500 غلطیاں) اور جو نہیں ہیں (جیسے 400 غلطیاں)۔

خام ہر چیز کو لاگو کرنے کی کوشش کرنا بہت جلد بھاری پڑ سکتا ہے۔ fetch()یہی وجہ ہے کہ مجھے لائبریریاں پسند ہیں۔ ky یہ واقعی مفید ہے۔ کے ساتھ kyآپ آسانی سے دوبارہ کوششوں کی تعداد بتا سکتے ہیں اور یہ دوبارہ کوشش کرنے کی منطق کو خود بخود سنبھال لے گا، بشمول ایکسپونینشل بیک آف اور مخصوص قسم کی غلطیوں کے لیے دوبارہ کوشش کرنا۔ اس میں بلٹ ان کینسل فنکشن بھی ہے۔ AbortControllerیہ آپ کی موجودہ منسوخی منطق کے ساتھ ضم کرنا آسان بناتا ہے۔

چلو شامل کرتے ہیں ky ہمارے پروجیکٹ پر جائیں اور دیکھیں کہ ہمارے کوڈ کو کس طرح آسان بنایا گیا ہے۔

cd frontend
npm install ky

اس کے بعد آپ اسے استعمال کرنے کے لیے اپنے فرنٹ اینڈ کوڈ کو اپ ڈیٹ کر سکتے ہیں۔ ky اس کے بجائے fetch():

import ky from 'ky';

...

fetchBtn.addEventListener('click', async () => {
  const ticketId = ticketIdInput.value.trim();
  
  if (!ticketId) {
    alert('Please enter a ticket ID');
    return;
  }

  // Abort any in-flight request for this queue before starting a new one
  if (currentController) {
    currentController.abort();
  }
  currentController = new AbortController();
  setLoadingState(true);

  try {
    const data = await ky
      .get(`/tickets/${ticketId}/nextNumber`, { signal: currentController.signal })
      .json();
    
    // Append to DOM
    ...
  } catch (error) {
    if (error.name === 'AbortError') return;
    console.error('Error fetching ticket:', error);
  } finally {
    setLoadingState(false);
  }
});

کے ساتھ kyآپ آسان اختیارات کا استعمال کرتے ہوئے آسانی سے دوبارہ کوششیں بھی شامل کر سکتے ہیں۔

const data = await ky
  .get(`/tickets/${ticketId}/nextNumber`, { 
    signal: currentController.signal,
    retry: {
      limit: 3, // Retry up to 3 times
      methods: ['get'], // Only retry GET requests
      statusCodes: [500], // Only retry on 500 errors
      backoffLimit: 10000 // Maximum delay of 10 seconds between retries
    }
  })
  .json();

بہت صاف، ٹھیک ہے؟ یہ آپ کو دوبارہ کوشش کرنے کی تمام منطق خود لکھے بغیر دوبارہ کوششوں کو سنبھالنے کی اجازت دیتا ہے، اور آپ کو مختلف اختیارات کا استعمال کرتے ہوئے دوبارہ کوشش کرنے کے رویے کو آسانی سے اپنی مرضی کے مطابق کرنے کی اجازت دیتا ہے۔

ڈوری ky دوبارہ کوشش کریں 03-retries آپ ریپوزٹری میں برانچ پر جا کر مکمل عمل درآمد دیکھ سکتے ہیں۔

git checkout 03-retries
npm install
npm run dev

اس نے ہمیں ایک سادہ فعالیت تیار کرنے کی اجازت دی۔ fetch() یہ زیادہ مضبوط نیٹ ورکنگ پیٹرن کی درخواست کرتا ہے جو سست نیٹ ورکس، خراب ردعمل، بے ترتیب ناکامیوں، اور کم سے کم کوڈ اور پیچیدگی کے ساتھ دوبارہ کوشش کر سکتے ہیں۔

یقینا ky بہت سی لائبریریوں میں سے ایک ہے جو ان نمونوں میں مدد کر سکتی ہے۔ مثال کے طور پر axios یہ ایک اور مقبول انتخاب ہے۔

پیداوار کے لئے تیار پیٹرن

زیادہ تر معاملات میں، آپ کو اپنی ایپ کے نیٹ ورکنگ کو مزید لچکدار اور پروڈکشن کے لیے تیار کرنے کے لیے بس یہی ضرورت ہے۔ تاہم، پروڈکشن گریڈ APIs کو اکثر دوبارہ کوشش کرنے اور منسوخ کرنے کے علاوہ اضافی نمونوں اور خصوصیات کی ضرورت ہوتی ہے۔

مثال کے طور پر، آپ نیٹ ورک کی غیر ضروری درخواستوں کو روکنے کے لیے کیشنگ کو لاگو کر سکتے ہیں۔ یا، چونکہ آپ کا بیک اینڈ ریٹ لمیٹڈ ہے، آپ کو سرور کو اوور لوڈ کرنے سے بچنے کے لیے کلائنٹ سائیڈ ریٹ محدود کرنے یا سرکٹ بریکرز کو لاگو کرنے کی ضرورت ہے۔ اگر آپ کے پاس تقسیم شدہ بیک اینڈ ہے، تو آپ کو متعدد سروسز میں درخواستوں کو ٹریک کرنے کے لیے درخواست کی ٹریکنگ اور ارتباطی IDs کو لاگو کرنے کی ضرورت پڑ سکتی ہے۔

ان موضوعات کا مختصراً احاطہ کرنے کے لیے، میں درج ذیل لائبریریوں کا تعارف کراؤں گا۔ ffetch. ffetch یہ ایک جدید درآمدی ریپر ہے جو ان میں سے بہت سی خصوصیات کو مقامی طور پر فراہم کرتا ہے، بشمول دوبارہ کوششیں، منسوخی، کیشنگ، اور بہت کچھ۔ اس میں ایک بہت لچکدار API بھی ہے جو آپ کو پلگ ان اور مڈل ویئر کا استعمال کرتے ہوئے اس کے رویے کو اپنی مرضی کے مطابق کرنے کی اجازت دیتا ہے۔

فرنٹ اینڈ کوڈ کو دوبارہ لکھیں جسے آپ استعمال کرنا چاہتے ہیں۔ ffetch اسے کچھ اس طرح نظر آنا چاہئے:

// frontend/main.js
import { createClient } from '@fetchkit/ffetch';

...

const api = createClient({
  timeout: 10000,
  retries: 3,
  throwOnHttpError: true, // Automatically throw for HTTP errors
  shouldRetry: ({ response }) => response?.status === 500 // Only retry on 500 errors
});

...

پھر آپ کے کلک ہینڈلر میں:

const response = await api(`/tickets/${ticketId}/nextNumber`, {
      signal: currentController.signal
    });
    const data = await response.json();

کوڈ یہاں موجود ہے: 04-ffetch آپ ریپوزٹری میں برانچ پر جا کر مکمل عمل درآمد دیکھ سکتے ہیں۔

git checkout 04-ffetch
npm install
npm run dev

شرح کی حد

زیادہ تر API میں شرح کو محدود کرنے کی کچھ شکل ہوتی ہے۔ اس کا مطلب ہے کہ اگر آپ مختصر وقت میں بہت زیادہ درخواستیں بھیجتے ہیں، تو سرور انہیں اس طرح مسترد کرنا شروع کر دے گا: 429 Too Many Requests غلطی اس سے نمٹنے کے لیے، آپ اس بات کو یقینی بنانے کے لیے کلائنٹ سائڈ ریٹ کو محدود کر سکتے ہیں کہ سرور کی حد سے تجاوز نہ کیا جائے۔

کے ساتھ ffetchکارروائی کرنے کے بجائے، آپ جوابات کی شرح کو محدود کرنے کے لیے مشترکہ دوبارہ کوشش کی پالیسی کو مرکزی بنا سکتے ہیں۔ 429 ہر کال سائٹ پر عارضی طور پر۔ ایک عملی نقطہ نظر یہ ہے کہ صرف چند بار دوبارہ کوشش کی جائے اور ایک کفایتی بیک آف کو شامل کیا جائے تاکہ دوبارہ کوشش کی گئی درخواستوں کو فاصلہ بنایا جائے۔

import { createClient } from '@fetchkit/ffetch';

const api = createClient({
  timeout: 10000,
  retries: 2,
  throwOnHttpError: true,
  shouldRetry: ({ response }) => response?.status === 429, // Only retry on 429 errors
  retryDelay: ({ attempt }) => 2 ** attempt * 200 // Exponential backoff: 200ms, 400ms
});

سرکٹ بریکر

شرح کو محدود کرنا اور بیک اینڈ کی بندش کا تعلق ہے لیکن ایک جیسا نہیں۔ سرکٹ بریکر ایک حد تک پہنچنے کے بعد آؤٹ باؤنڈ کالوں کو عارضی طور پر روک کر اور پھر بعد میں ریکوری کی تصدیق کی اجازت دے کر بار بار آنے والی غلطیوں کا ازالہ کرتے ہیں۔

میں ffetchیہ سرکٹ پلگ ان کا استعمال کرتے ہوئے سنبھالا جا سکتا ہے.

import { createClient } from '@fetchkit/ffetch';
import { circuitPlugin } from '@fetchkit/ffetch/plugins/circuit';

const api = createClient({
  timeout: 10000,
  retries: 2,
  throwOnHttpError: true,
  shouldRetry: ({ response }) =>
    [500, 502, 503, 504].includes(response?.status ?? 0),
  plugins: [
    circuitPlugin({
      threshold: 5,
      reset: 30000
    })
  ]
});

یہ کسی واقعے کی صورت میں فرنٹ اینڈ کو تیزی سے ناکام ہونے میں مدد کرتا ہے، غیر صحت مند خدمات پر غیر ضروری بوجھ کو کم کرتا ہے، اور ری سیٹ ونڈو کے بعد خود بخود ٹھیک ہوجاتا ہے۔

درخواستوں کو ضم کریں۔

کچھ معاملات میں، آپ کے پاس آپ کی ایپ کے متعدد اجزاء یا حصے ہو سکتے ہیں جن کو ایک ہی ڈیٹا حاصل کرنے کی ضرورت ہے۔ (پچھلے مضمون کے برعکس جہاں صارف نے فوری طور پر بٹن پر کلک کیا، یہاں آپ کو حقیقت میں مکمل جواب کی ضرورت ہو سکتی ہے۔)

متعدد یکساں درخواستیں بھیجنے کے بجائے، آپ لاگو کر سکتے ہیں: درخواستوں کو ضم کریں۔ ان کو ایک درخواست میں یکجا کریں اور جواب کا اشتراک کریں۔ ffetch اس کے لیے بلٹ ان سپورٹ موجود ہے۔ dedupe پلگ انز:

import { createClient } from '@fetchkit/ffetch';
import { dedupePlugin } from '@fetchkit/ffetch/plugins/dedupe';

const api = createClient({
  timeout: 10000,
  retries: 2,
  throwOnHttpError: true,
  plugins: [dedupePlugin({ ttl: 1000 })]
});

// Same request fired twice -> one in-flight request, shared result
const [r1, r2] = await Promise.all([
  api('/tickets/1/nextNumber'),
  api('/tickets/1/nextNumber')
]);

کیشنگ

کیشنگ جواب کو ذخیرہ کرتی ہے تاکہ اسی وسائل کے لیے مستقبل کی درخواستوں پر نیٹ ورک تک پہنچے بغیر کارروائی کی جا سکے۔ یہ بینڈوتھ کو بچاتا ہے، تاخیر کو کم کرتا ہے، اور آپ کے پسدید کو بے کار بوجھ سے بچاتا ہے۔

نیچے دی گئی تکنیکوں میں سے کوئی بھی مخصوص درآمدی لائبریری کے لیے مخصوص نہیں ہے۔ باقاعدہ لائبریریوں کے ساتھ کام کرتا ہے۔ fetch, ky, axiosیا کچھ اور۔

اس کی آسان ترین شکل میں، کیشنگ کی کلائنٹ کی طرف سے کوئی قیمت نہیں ہے۔ ایک بار جب سرور درست جوابی ہیڈرز سیٹ کر لیتا ہے، براؤزر خود بخود ہر چیز کو سنبھال لیتا ہے۔

Cache-Control: max-age=60, stale-while-revalidate=30

max-age=60 اس کا مطلب ہے کہ براؤزر نیٹ ورک کو چھوئے بغیر 60 سیکنڈ تک کیشڈ جوابات پیش کرے گا۔ stale-while-revalidate=30 اس ونڈو کو پھیلائیں۔ کیشے کی میعاد ختم ہونے کے بعد اضافی 30 سیکنڈ کے لیے، براؤزر فوری طور پر پرانی کاپی پیش کرتا ہے جبکہ بیک گراؤنڈ میں ایک نئی کاپی حاصل کرتا ہے۔

یہ عام طور پر صحیح پہلا اقدام ہے۔ کلائنٹ سائیڈ کیشنگ کوڈ لکھنے سے پہلے، یقینی بنائیں کہ آپ کا API مناسب نتائج دے سکتا ہے۔ Cache-Control ہیڈر

ان میموری کیش

اگر آپ کو مزید دانے دار کنٹرول کی ضرورت ہے یا آپ کا API ہیڈر سیٹ نہیں کر سکتا، تو آپ سادہ JavaScript کے ساتھ جواب کو براہ راست کیش کر سکتے ہیں۔ Map. خیال یہ ہے کہ یو آر ایل میں کلید کریں، جواب کو ٹائم اسٹیمپ کے ساتھ اسٹور کریں، اور اگر آئٹم ابھی بھی تازہ ہے تو نیٹ ورک کو چھوڑ دیں۔

const cache = new Map();
const TTL_MS = 60_000; // 1 minute

async function cachedFetch(url, options) {
  const cached = cache.get(url);
  if (cached && Date.now() - cached.timestamp < TTL_MS) {
    return cached.data;
  }

  const response = await fetch(url, options);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);

  const data = await response.json();
  cache.set(url, { data, timestamp: Date.now() });
  return data;
}

یہ جان بوجھ کر آسان ہے۔ بنیادی حد یہ ہے کہ جب آپ صفحہ کو دوبارہ لوڈ کرتے ہیں تو وہ غائب ہو جاتے ہیں اور ٹیبز کے درمیان اشتراک نہیں کیا جاتا ہے۔ یہ زیادہ تر قلیل مدتی UI ریاستوں کے لیے ٹھیک ہے۔

اسٹوریج سپورٹ کیشے

اگر آپ کو صفحہ کو دوبارہ لوڈ کرتے وقت کیش کی ضرورت ہو تو، اس پر لکھیں: localStorage یا sessionStorage اس کے بجائے:

function getCached(key) {
  try {
    const raw = localStorage.getItem(key);
    if (!raw) return null;
    const { data, expiresAt } = JSON.parse(raw);
    if (Date.now() > expiresAt) {
      localStorage.removeItem(key);
      return null;
    }
    return data;
  } catch {
    return null;
  }
}

function setCached(key, data, ttlMs = 60_000) {
  localStorage.setItem(key, JSON.stringify({ data, expiresAt: Date.now() + ttlMs }));
}

async function fetchWithStorage(url) {
  const key = `cache:${url}`;
  const cached = getCached(key);
  if (cached) return cached;

  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);

  const data = await response.json();
  setCached(key, data);
  return data;
}

براہ کرم ذہن میں رکھیں localStorage یہ ہم وقت ساز ہے، زیادہ سے زیادہ 5 MB تک محدود ہے، اور صرف تاروں کو اسٹور کرتا ہے۔ یہ چھوٹے، کبھی کبھار تبدیل ہونے والے ڈیٹا کے لیے موزوں ہے، جیسے صارف کی ترجیحات یا حوالہ تلاش کرنا۔ بڑے ڈیٹاسیٹس کے لیے، درج ذیل پر غور کریں: IndexedDBیا idb-keyval جیسی لائبریری جو اسے ایک آسان API میں لپیٹتی ہے۔

کیشے کو باطل کریں۔

کیشنگ ایک کلاسک مسئلہ کے بارے میں لاتا ہے: باسی ڈیٹا۔ چند عمومی حکمت عملی اس مسئلے کو حل کرنے میں آپ کی مدد کر سکتی ہیں:

  • وقت پر مبنی میعاد ختم ہونے (TTL): اوپر کی مثال میں کیا استعمال ہوا ہے؟ یہ آسان ہے، لیکن آپ کا کیش ایک سال تک درست نہیں ہو سکتا۔ TTL_MS ملی سیکنڈ

  • دستی باطل: تبدیلی کے بعد (POST/PUT/DELETE)، اگلے پڑھنے پر نیا ڈیٹا حاصل کرنے کے لیے متعلقہ کیش کلید کو واضح طور پر حذف کریں۔

  • باطل ہونے کے دوران دوبارہ تصدیق: فوری طور پر کیش شدہ کاپی پیش کرتا ہے اور پھر اسے پس منظر میں تازہ کرتا ہے۔ براؤزر Cache-Control ہیڈرز مقامی طور پر اس کی حمایت کرتے ہیں۔ آپ کیش شدہ اقدار کو واپس کرکے اور پس منظر کو متحرک کرکے اسے دستی طور پر نقل کرسکتے ہیں۔ fetch ایک ہی وقت میں.

صحیح انتخاب اس بات پر منحصر ہے کہ آپ کا ڈیٹا کتنی بار تبدیل ہوتا ہے اور آپ کتنی باسی برداشت کر سکتے ہیں۔

نتیجہ

اس مضمون میں، ہم نے کچھ آسان کے ساتھ شروع کیا. fetch() حقیقی دنیا کے نیٹ ورکنگ کے مسائل جیسے کہ برے جوابات، سست نیٹ ورکس، بے ترتیب ناکامیاں، دوبارہ کوششیں، منسوخی، شرح کو محدود کرنا، سرکٹ بلاک کرنا، انضمام کی درخواست، اور کیشنگ جیسے نمونوں کو بلایا اور بتدریج شامل کیا گیا۔

ہم نے درج ذیل لائبریریاں بھی متعارف کروائی ہیں۔ ky اور ffetch یہ ان میں سے بہت سی خصوصیات کو مقامی طور پر فراہم کرتا ہے، جس سے پہیے کو دوبارہ ایجاد کیے بغیر پروڈکشن کے لیے تیار نیٹ ورکنگ کوڈ لکھنا آسان ہو جاتا ہے۔

آپ کو اپنے پہلے دن ان سب کی ضرورت نہیں ہے۔ سے شروع کریں۔ res.ok اور AbortController. اگر آپ کو ایرر لاگ میں عارضی خرابیاں نظر آنے لگیں تو دوبارہ کوشش کریں۔ اگر ڈاون اسٹریم انحصار میں استحکام کے مسائل ہوں تو سرکٹ بریکرز شامل کریں۔

مسئلہ کو سطح پر آنے دیں اور پھر پیٹرن کا اطلاق کریں۔ کلید یہ ہے کہ فوائد اور نقصانات کو سمجھیں اور اپنے مخصوص استعمال کے معاملے کے لیے صحیح ٹول کا انتخاب کریں۔

آپ کے ٹول کٹ میں ان نمونوں کے ساتھ، آپ لچکدار، صارف دوست ایپلی کیشنز بنانے کے لیے بہتر طریقے سے لیس ہوں گے جو حقیقی دنیا کے نیٹ ورکس کی غیر متوقع صلاحیت کو سنبھال سکتے ہیں۔

اوپر تک سکرول کریں۔