paint-brush
জাভাস্ক্রিপ্ট বর্ধিত ফর্মগুলিতে ডুপ্লিকেট আনার অনুরোধগুলি কীভাবে বাতিল করবেন সে সম্পর্কে একটি নির্দেশিকাদ্বারা@austingil
2,570 পড়া
2,570 পড়া

জাভাস্ক্রিপ্ট বর্ধিত ফর্মগুলিতে ডুপ্লিকেট আনার অনুরোধগুলি কীভাবে বাতিল করবেন সে সম্পর্কে একটি নির্দেশিকা

দ্বারা Austin Gil8m2023/02/10
Read on Terminal Reader
Read this story w/o Javascript

অতিদীর্ঘ; পড়তে

আপনি ভুলবশত একটি ডুপ্লিকেট-অনুরোধ/রেস-কন্ডিশন বাগ প্রবর্তন করেছেন এমন একটি ভাল সুযোগ রয়েছে। আজ, আমি আপনাকে সমস্যাটি এবং এটি এড়ানোর জন্য আমার সুপারিশগুলি নিয়ে চলে যাব। এখানে মূল সমস্যা হল `event.preventDefault()`। এই পদ্ধতিটি ব্রাউজারকে নতুন পৃষ্ঠা লোড করার এবং ফর্ম জমা দেওয়ার ডিফল্ট আচরণ করতে বাধা দেয়।
featured image - জাভাস্ক্রিপ্ট বর্ধিত ফর্মগুলিতে ডুপ্লিকেট আনার অনুরোধগুলি কীভাবে বাতিল করবেন সে সম্পর্কে একটি নির্দেশিকা
Austin Gil HackerNoon profile picture

আপনি যদি কখনও জাভাস্ক্রিপ্ট 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 অনুরোধ ট্রিগার করে এবং সম্পূর্ণ হওয়ার পরে, আপনার অ্যাপ্লিকেশন তাদের পরিবর্তনগুলির সাথে পৃষ্ঠাটি আপডেট করে। ক্রমবর্ধমান অনুরোধগুলি সমাধান করার কারণে ব্যবহারকারী শেষ পর্যন্ত ভুল তথ্য দেখতে পারে।


এটি নন-জাভাস্ক্রিপ্ট বিশ্বে একটি অ-ইস্যু কারণ ব্রাউজার পূর্ববর্তী যেকোনো অনুরোধ বাতিল করে এবং সাম্প্রতিক অনুরোধটি সম্পূর্ণ হওয়ার পরে পৃষ্ঠাটি লোড করে, সবচেয়ে আপ-টু-ডেট সংস্করণ লোড করে। কিন্তু পাতা রিফ্রেশ হিসাবে সেক্সি হয় না.


জাভাস্ক্রিপ্ট প্রেমীদের জন্য ভাল খবর হল যে আমাদের উভয়ই থাকতে পারে সেক্সি ব্যবহারকারীর অভিজ্ঞতা এবং একটি সামঞ্জস্যপূর্ণ UI!


আমাদের শুধু একটু বেশি কাজ করতে হবে।


আপনি যদি 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: ব্যবহারকারী একটি অনুরোধ বাতিল করেছে।" এবং আপনি যদি নেটওয়ার্ক ট্যাবটি অন্বেষণ করেন, তাহলে আপনি স্ট্যাটাস টেক্সট "(বাতিল)" সহ একটি ব্যর্থ অনুরোধ দেখতে পাবেন৷


জাভাস্ক্রিপ্ট কনসোল খোলার সাথে নেটওয়ার্কে Chrome dev টুলগুলি খোলা হয়েছে৷ কনসোলে কোড আছে "const controller = new AbortController();fetch('', { signal: controller.signal });controller.abort()", এর পরে ব্যতিক্রম, "Uncaught (প্রতিশ্রুতি অনুযায়ী) DOMexception: The ব্যবহারকারী একটি অনুরোধ বাতিল করেছে।" নেটওয়ার্কে, স্ট্যাটাস টেক্সট "(বাতিল)" সহ "স্থানীয় হোস্ট" করার অনুরোধ রয়েছে

এটি মাথায় রেখে, আমরা আমাদের ফর্মের জমা হ্যান্ডলারে একটি 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 অন্তর্ভুক্ত করা সম্ভবত একটি ভাল ধারণা। এটি সত্যিই খুব খারাপ এটি ইতিমধ্যেই এপিআই-এর মধ্যে তৈরি করা হয়নি। কিন্তু আশা করি, এটি আপনাকে এটি অন্তর্ভুক্ত করার জন্য একটি ভাল পদ্ধতি দেখায়।


এটিও উল্লেখ করার মতো যে এই পদ্ধতিটি ব্যবহারকারীকে সাবমিট বোতামটি একগুচ্ছ বার স্প্যাম করা থেকে বাধা দেয় না। বোতামটি এখনও ক্লিকযোগ্য, এবং অনুরোধটি এখনও বন্ধ হয়ে যায়, এটি প্রতিক্রিয়াগুলির সাথে মোকাবিলা করার আরও সামঞ্জস্যপূর্ণ উপায় প্রদান করে।


দুর্ভাগ্যবশত, যদি একজন ব্যবহারকারী একটি জমা বোতাম স্প্যাম করে , সেই অনুরোধগুলি এখনও আপনার ব্যাকএন্ডে যাবে এবং অপ্রয়োজনীয় সংস্থানগুলির একটি গুচ্ছ ব্যবহার করতে পারে।


কিছু নিষ্পাপ সমাধান সাবমিট বোতামটি অক্ষম করতে পারে, একটি ব্যবহার করে debounce , অথবা পূর্ববর্তীগুলি সমাধান করার পরে শুধুমাত্র নতুন অনুরোধ তৈরি করা। আমি এই বিকল্পগুলি পছন্দ করি না কারণ তারা ব্যবহারকারীর অভিজ্ঞতাকে ধীর করার উপর নির্ভর করে এবং শুধুমাত্র ক্লায়েন্টের দিকে কাজ করে।


তারা স্ক্রিপ্টেড অনুরোধের মাধ্যমে অপব্যবহারকে সম্বোধন করে না।


আপনার সার্ভারে অনেক অনুরোধ থেকে অপব্যবহার মোকাবেলা করতে, আপনি সম্ভবত কিছু সেট আপ করতে চান হার সীমিত . এটি এই পোস্টের সুযোগের বাইরে যায়, তবে এটি উল্লেখ করার মতো ছিল।


এটাও উল্লেখ করার মতো যে হার সীমিত করা ডুপ্লিকেট অনুরোধ, রেসের অবস্থা এবং অসঙ্গতিপূর্ণ UI আপডেটের মূল সমস্যার সমাধান করে না। আদর্শভাবে, আমরা উভয় প্রান্ত আবরণ উভয় ব্যবহার করা উচিত.


যাইহোক, আমি আজকের জন্য এটিই পেয়েছি। আপনি যদি এই একই বিষয় কভার করে এমন একটি ভিডিও দেখতে চান তবে এটি দেখুন।

পড়ার জন্য আপনাকে অনেক ধন্যবাদ. আপনি যদি এই নিবন্ধটি পছন্দ করেন, অনুগ্রহ করে এটা ভাগ করে নিন . এটা আমাকে সমর্থন করার সেরা উপায় এক. আপনি এটিও করতে পারেন আমার নিউজলেটার জন্য সাইন আপ করুন বা আমাকে টুইটার এ অনুসরন কর আপনি জানতে চান যখন নতুন নিবন্ধ প্রকাশিত হয়.


মূলত প্রকাশিত austingil.com .