আপনি যদি কখনও জাভাস্ক্রিপ্ট fetch
এপিআই ব্যবহার করে থাকেন একটি ফর্ম জমা বাড়াতে, তাহলে আপনি ভুলবশত একটি ডুপ্লিকেট-রিকোয়েস্ট/রেস-কন্ডিশন বাগ প্রবর্তন করেছেন। আজ, আমি আপনাকে সমস্যাটি এবং এটি এড়াতে আমার সুপারিশগুলি নিয়ে চলে যাব।
(আপনি যদি পছন্দ করেন তাহলে ভিডিও শেষে)
এর একটি খুব মৌলিক বিবেচনা করা যাক
<form method="post"> <label for="name">Name</label> <input id="name" name="name" /> <button>Submit</button> </form>
যখন আমরা সাবমিট বাটনে চাপ দিব, ব্রাউজার পুরো পৃষ্ঠা রিফ্রেশ করবে।
সাবমিট বোতামটি ক্লিক করার পরে ব্রাউজারটি কীভাবে পুনরায় লোড হয় তা লক্ষ্য করুন।
পৃষ্ঠা রিফ্রেশ সবসময় আমরা আমাদের ব্যবহারকারীদের অফার করতে চাই না, তাই একটি সাধারণ বিকল্প ব্যবহার করা হয়fetch
API ব্যবহার করে ফর্ম ডেটা জমা দিতে।
একটি সরল পদ্ধতি নীচের উদাহরণ মত দেখতে হতে পারে.
পৃষ্ঠা (বা উপাদান) মাউন্ট করার পরে, আমরা ফর্ম DOM নোড ধরি, একটি ইভেন্ট লিসেনার যোগ করি যা ফর্ম ব্যবহার করে একটি fetch
অনুরোধ তৈরি করেpreventDefault()
পদ্ধতিকে কল করি।
const form = document.querySelector('form'); form.addEventListener('submit', handleSubmit); function handleSubmit(event) { const form = event.currentTarget; fetch(form.action, { method: form.method, body: new FormData(form) }); event.preventDefault(); }
এখন, কোন জাভাস্ক্রিপ্ট হটশট GET বনাম পোস্ট সম্পর্কে আমাকে টুইট করা শুরু করার আগে এবং অনুরোধের বডি এবংfetch
অনুরোধটি ইচ্ছাকৃতভাবে সহজ রাখছি কারণ এটি মূল ফোকাস নয়।
এখানে মূল সমস্যা হল event.preventDefault()
। এই পদ্ধতিটি ব্রাউজারকে নতুন পৃষ্ঠা লোড করার এবং ফর্ম জমা দেওয়ার ডিফল্ট আচরণ করতে বাধা দেয়।
এখন, যদি আমরা স্ক্রিনের দিকে তাকাই এবং সাবমিট চাপি, আমরা দেখতে পাব যে পৃষ্ঠাটি পুনরায় লোড হচ্ছে না, তবে আমরা আমাদের নেটওয়ার্ক ট্যাবে HTTP অনুরোধটি দেখতে পাচ্ছি।
লক্ষ্য করুন ব্রাউজারটি সম্পূর্ণ পৃষ্ঠা পুনরায় লোড করে না।
দুর্ভাগ্যবশত, ডিফল্ট আচরণ প্রতিরোধ করতে JavaScript ব্যবহার করে, আমরা আসলে একটি বাগ প্রবর্তন করেছি যা ডিফল্ট ব্রাউজার আচরণে নেই।
আমরা যখন প্লেইন ব্যবহার করি
যদি আমরা এটিকে জাভাস্ক্রিপ্ট উদাহরণের সাথে তুলনা করি, আমরা দেখতে পাব যে সমস্ত অনুরোধ পাঠানো হয়েছে, এবং তাদের সবগুলি বাতিল না করেই সম্পূর্ণ হয়েছে।
এটি একটি সমস্যা হতে পারে কারণ যদিও প্রতিটি অনুরোধের জন্য আলাদা পরিমাণ সময় লাগতে পারে, তবে তারা শুরু করার চেয়ে ভিন্ন ক্রমে সমাধান করতে পারে। এর মানে হল যদি আমরা সেই অনুরোধগুলির রেজোলিউশনে কার্যকারিতা যোগ করি, তাহলে আমাদের কিছু অপ্রত্যাশিত আচরণ হতে পারে।
একটি উদাহরণ হিসাবে, আমরা প্রতিটি অনুরোধের জন্য বৃদ্ধির জন্য একটি ভেরিয়েবল তৈরি করতে পারি (" totalRequestCount
")। যতবার আমরা handleSubmit
ফাংশন চালাই, আমরা মোট গণনা বৃদ্ধি করতে পারি এবং বর্তমান অনুরোধটি ট্র্যাক করতে বর্তমান সংখ্যাটি ক্যাপচার করতে পারি (" thisRequestNumber
")।
যখন একটি fetch
অনুরোধ সমাধান হয়, আমরা কনসোলে এর সংশ্লিষ্ট নম্বর লগ করতে পারি।
const form = document.querySelector('form'); form.addEventListener('submit', handleSubmit); let totalRequestCount = 0 function handleSubmit(event) { totalRequestCount += 1 const thisRequestNumber = totalRequestCount const form = event.currentTarget; fetch(form.action, { method: form.method, body: new FormData(form) }).then(() => { console.log(thisRequestNumber) }) event.preventDefault(); }
এখন, যদি আমরা সেই সাবমিট বোতামটি কয়েকবার ভেঙে ফেলি, তাহলে আমরা দেখতে পারি যে কনসোলে বিভিন্ন সংখ্যা প্রিন্ট করা হয়েছে: 2, 3, 1, 4, 5। এটি নেটওয়ার্ক গতির উপর নির্ভর করে, কিন্তু আমি মনে করি আমরা সবাই একমত হতে পারি যে এটি আদর্শ নয়।
একটি দৃশ্যকল্প বিবেচনা করুন যেখানে একজন ব্যবহারকারী পর্যায়ক্রমে বেশ কয়েকটি fetch
অনুরোধ ট্রিগার করে এবং সম্পূর্ণ হওয়ার পরে, আপনার অ্যাপ্লিকেশন তাদের পরিবর্তনগুলির সাথে পৃষ্ঠাটি আপডেট করে। ক্রমবর্ধমান অনুরোধগুলি সমাধান করার কারণে ব্যবহারকারী শেষ পর্যন্ত ভুল তথ্য দেখতে পারে।
এটি নন-জাভাস্ক্রিপ্ট বিশ্বে একটি অ-ইস্যু কারণ ব্রাউজার পূর্ববর্তী যেকোনো অনুরোধ বাতিল করে এবং সাম্প্রতিক অনুরোধটি সম্পূর্ণ হওয়ার পরে পৃষ্ঠাটি লোড করে, সবচেয়ে আপ-টু-ডেট সংস্করণ লোড করে। কিন্তু পাতা রিফ্রেশ হিসাবে সেক্সি হয় না.
জাভাস্ক্রিপ্ট প্রেমীদের জন্য ভাল খবর হল যে আমাদের উভয়ই থাকতে পারে
আমাদের শুধু একটু বেশি কাজ করতে হবে।
আপনি যদি fetch
API ডকুমেন্টেশন দেখেন, আপনি দেখতে পাবেন যে AbortController
ব্যবহার করে ফেচ বাতিল করা সম্ভব এবং fetch
বিকল্পগুলির signal
সম্পত্তি। এটা এই মত কিছু দেখায়:
const controller = new AbortController(); fetch(url, { signal: controller.signal });
fetch
অনুরোধে AbortContoller
এর সংকেত প্রদান করে, AbortContoller
এর abort
পদ্ধতিটি ট্রিগার হলে আমরা অনুরোধটি বাতিল করতে পারি।
আপনি জাভাস্ক্রিপ্ট কনসোলে একটি পরিষ্কার উদাহরণ দেখতে পারেন। একটি AbortController
তৈরি করার চেষ্টা করুন, fetch
অনুরোধ শুরু করুন, তারপর অবিলম্বে abort
পদ্ধতিটি কার্যকর করুন।
const controller = new AbortController(); fetch('', { signal: controller.signal }); controller.abort()
আপনি অবিলম্বে কনসোলে মুদ্রিত একটি ব্যতিক্রম দেখতে হবে. ক্রোমিয়াম ব্রাউজারগুলিতে, এটি বলা উচিত, "অপরাধিত (প্রতিশ্রুতিতে) DOMexception: ব্যবহারকারী একটি অনুরোধ বাতিল করেছে।" এবং আপনি যদি নেটওয়ার্ক ট্যাবটি অন্বেষণ করেন, তাহলে আপনি স্ট্যাটাস টেক্সট "(বাতিল)" সহ একটি ব্যর্থ অনুরোধ দেখতে পাবেন৷
এটি মাথায় রেখে, আমরা আমাদের ফর্মের জমা হ্যান্ডলারে একটি AbortController
যোগ করতে পারি। যুক্তি নিম্নরূপ হবে:
AbortController
চেক করুন। যদি একটি বিদ্যমান থাকে, এটি বাতিল করুন.
AbortController
তৈরি করুন যা পরবর্তী অনুরোধে বাতিল করা যেতে পারে।
AbortController
সরিয়ে দিন।
এটি করার বিভিন্ন উপায় রয়েছে, তবে আমি প্রতিটি জমা দেওয়া <form>
DOM নোড এবং এর সংশ্লিষ্ট AbortController
এর মধ্যে সম্পর্ক সংরক্ষণ করতে একটি WeakMap
ব্যবহার করব। যখন একটি ফর্ম জমা দেওয়া হয়, আমরা সেই অনুযায়ী WeakMap
চেক এবং আপডেট করতে পারি।
const pendingForms = new WeakMap(); function handleSubmit(event) { const form = event.currentTarget; const previousController = pendingForms.get(form); if (previousController) { previousController.abort(); } const controller = new AbortController(); pendingForms.set(form, controller); fetch(form.action, { method: form.method, body: new FormData(form), signal: controller.signal, }).then(() => { pendingForms.delete(form); }); event.preventDefault(); } const forms = document.querySelectorAll('form'); for (const form of forms) { form.addEventListener('submit', handleSubmit); }
মূল জিনিসটি একটি গর্ভপাত কন্ট্রোলারকে তার সংশ্লিষ্ট ফর্মের সাথে সংযুক্ত করতে সক্ষম হচ্ছে। ফর্মের DOM নোডটিকে WeakMap
এর কী হিসাবে ব্যবহার করা এটি করার একটি সুবিধাজনক উপায়।
এটির সাথে, আমরা fetch
অনুরোধে AbortController
এর সংকেত যোগ করতে পারি, কোনো পূর্ববর্তী নিয়ন্ত্রক বাতিল করতে পারি, নতুন যোগ করতে পারি এবং সম্পূর্ণ হওয়ার পরে সেগুলি মুছে ফেলতে পারি।
আশা করি, যে সব অর্থে তোলে.
এখন, যদি আমরা সেই ফর্মের সাবমিট বোতামটি কয়েকবার ছিঁড়ে ফেলি, আমরা দেখতে পাব যে সাম্প্রতিকতমটি ছাড়া সমস্ত API অনুরোধ বাতিল হয়ে যাবে।
এর মানে হল যে কোনো ফাংশন সেই HTTP প্রতিক্রিয়ায় সাড়া দিয়ে আপনার প্রত্যাশা অনুযায়ী আরও বেশি আচরণ করবে।
এখন, যদি আমরা উপরে আমাদের একই কাউন্টিং এবং লগিং লজিক ব্যবহার করি, তাহলে আমরা সাবমিট বোতামটি সাতবার স্মাশ করতে পারি এবং কনসোলে ছয়টি ব্যতিক্রম ( AbortController
এর কারণে) এবং একটি লগ "7" দেখতে পাব।
যদি আমরা আবার জমা দেই এবং অনুরোধটি সমাধানের জন্য পর্যাপ্ত সময় দেয়, তাহলে আমরা কনসোলে "8" দেখতে পাব। এবং যদি আমরা সাবমিট বোতামটি গুচ্ছ গুচ্ছ করে ফেলি, আবার, আমরা সঠিক ক্রমে ব্যতিক্রম এবং চূড়ান্ত অনুরোধ গণনা দেখতে পাব।
আপনি যদি একটি অনুরোধ বাতিল করার সময় কনসোলে DOM-এর ব্যতিক্রমগুলি দেখা এড়াতে আরও কিছু যুক্তি যোগ করতে চান, আপনি আপনার fetch
অনুরোধের পরে একটি .catch()
ব্লক যোগ করতে পারেন এবং ত্রুটিটির নাম " AbortError
" এর সাথে মেলে কিনা তা পরীক্ষা করতে পারেন:
fetch(url, { signal: controller.signal, }).catch((error) => { // If the request was aborted, do nothing if (error.name === 'AbortError') return; // Otherwise, handle the error here or throw it back to the console throw error });
এই পুরো পোস্টটি জাভাস্ক্রিপ্ট-বর্ধিত ফর্মগুলিতে ফোকাস করা হয়েছিল, তবে আপনি যখনই একটি fetch
অনুরোধ তৈরি করেন তখন একটি AbortController
অন্তর্ভুক্ত করা সম্ভবত একটি ভাল ধারণা। এটি সত্যিই খুব খারাপ এটি ইতিমধ্যেই এপিআই-এর মধ্যে তৈরি করা হয়নি। কিন্তু আশা করি, এটি আপনাকে এটি অন্তর্ভুক্ত করার জন্য একটি ভাল পদ্ধতি দেখায়।
এটিও উল্লেখ করার মতো যে এই পদ্ধতিটি ব্যবহারকারীকে সাবমিট বোতামটি একগুচ্ছ বার স্প্যাম করা থেকে বাধা দেয় না। বোতামটি এখনও ক্লিকযোগ্য, এবং অনুরোধটি এখনও বন্ধ হয়ে যায়, এটি প্রতিক্রিয়াগুলির সাথে মোকাবিলা করার আরও সামঞ্জস্যপূর্ণ উপায় প্রদান করে।
দুর্ভাগ্যবশত, যদি একজন ব্যবহারকারী একটি জমা বোতাম স্প্যাম করে , সেই অনুরোধগুলি এখনও আপনার ব্যাকএন্ডে যাবে এবং অপ্রয়োজনীয় সংস্থানগুলির একটি গুচ্ছ ব্যবহার করতে পারে।
কিছু নিষ্পাপ সমাধান সাবমিট বোতামটি অক্ষম করতে পারে, একটি ব্যবহার করে
তারা স্ক্রিপ্টেড অনুরোধের মাধ্যমে অপব্যবহারকে সম্বোধন করে না।
আপনার সার্ভারে অনেক অনুরোধ থেকে অপব্যবহার মোকাবেলা করতে, আপনি সম্ভবত কিছু সেট আপ করতে চান
এটাও উল্লেখ করার মতো যে হার সীমিত করা ডুপ্লিকেট অনুরোধ, রেসের অবস্থা এবং অসঙ্গতিপূর্ণ UI আপডেটের মূল সমস্যার সমাধান করে না। আদর্শভাবে, আমরা উভয় প্রান্ত আবরণ উভয় ব্যবহার করা উচিত.
যাইহোক, আমি আজকের জন্য এটিই পেয়েছি। আপনি যদি এই একই বিষয় কভার করে এমন একটি ভিডিও দেখতে চান তবে এটি দেখুন।
পড়ার জন্য আপনাকে অনেক ধন্যবাদ. আপনি যদি এই নিবন্ধটি পছন্দ করেন, অনুগ্রহ করে
মূলত প্রকাশিত