এই দুটি শীর্ষ উত্তর দেওয়া উভয়ই ভুল। একযোগে মডেল এবং ইভেন্টের লুপের MDN বিবরণটি দেখুন এবং কী চলছে তা স্পষ্ট হওয়া উচিত (যে MDN রিসোর্সটি একটি সত্যই রত্ন)। এবং সহজভাবে ব্যবহার setTimeout
করা আপনার সামান্য সমস্যাটিকে "সমাধান" করার পাশাপাশি আপনার কোডে অপ্রত্যাশিত সমস্যা যুক্ত করতে পারে।
আসলে কি এখানে যাচ্ছে যে নয় "ব্রাউজার এখনও প্রস্তুত নাও হতে পারে তবু সম্পাতবিন্দু" অথবা উপর ভিত্তি করে কিছু "প্রতিটি লাইনে একটি ইভেন্ট কিউ ফিরে যোগ করা পরার যে হয়"।
jsfiddle DVK দ্বারা উপলব্ধ প্রকৃতপক্ষে একটি সমস্যা প্রকাশ করে, কিন্তু এটি জন্য তার ব্যাখ্যা সঠিক নয়।
তার কোডে যা ঘটছে তা হ'ল তিনি প্রথম ইভেন্টের কোনও ইভেন্ট হ্যান্ডলার সংযুক্ত click
করছেন#do
বোতামের ।
তারপরে, আপনি যখন আসলে বোতামটি ক্লিক করেন, message
ইভেন্ট হ্যান্ডলার ফাংশনটি উল্লেখ করে একটি তৈরি করা হয়, যা এতে যুক্ত হয় message queue
। যখন event loop
এই বার্তাটি পৌঁছে, এটি একটি সৃষ্টি frame
jsfiddle ক্লিকের ইভেন্ট হ্যান্ডলার থেকে ফাংশন কল সঙ্গে স্ট্যাক।
এবং এটি এখানে আকর্ষণীয় হয়ে ওঠে। আমরা জাভাস্ক্রিপ্টকে অবিচ্ছিন্ন হিসাবে ভাবতে অভ্যস্ত যে আমরা এই ক্ষুদ্র সত্যটিকে উপেক্ষা করার প্রবণতা করছি: পরবর্তী ফ্রেমটি কার্যকর করার আগে যে কোনও ফ্রেম পুরোপুরি কার্যকর করতে হবে । কোন সম্মতি নেই, মানুষ।
এটার মানে কি? এর অর্থ হ'ল যখনই কোনও বার্তা সারি থেকে কোনও ক্রিয়াকলাপ চাওয়া হয়, এটি উত্পন্ন স্ট্যাকটি খালি না করা অবধি এই সারিটিকে অবরুদ্ধ করে। অথবা, আরও সাধারণ পরিভাষায়, ফাংশনটি ফিরে না আসা পর্যন্ত এটি অবরুদ্ধ করে। এবং এটি সব কিছু অবরুদ্ধ করে ডিওএম রেন্ডারিং অপারেশন, স্ক্রোলিং এবং হোয়াট নোট সহ অবরুদ্ধ করে। আপনি যদি নিশ্চিতকরণ চান, তবে কেবলমাত্র ফ্রিডলটিতে দীর্ঘ চলমান অপারেশনের সময়কাল বাড়াতে চেষ্টা করুন (উদাহরণস্বরূপ, বাইরের লুপটি আরও 10 বার চালান) এবং আপনি লক্ষ্য করবেন যে এটি চলাকালীন আপনি পৃষ্ঠাটি স্ক্রোল করতে পারবেন না। যদি এটি দীর্ঘক্ষণ চলে তবে আপনার ব্রাউজার আপনাকে জিজ্ঞাসা করবে আপনি প্রক্রিয়াটি মেরে ফেলতে চান কিনা, কারণ এটি পৃষ্ঠাটিকে প্রতিক্রিয়াহীন করে তুলছে। ফ্রেমটি কার্যকর করা হচ্ছে, এবং ইভেন্ট লুপ এবং বার্তা সারি শেষ না হওয়া পর্যন্ত আটকে থাকবে।
তাহলে এই পাঠ্যটির পার্শ্ব-প্রতিক্রিয়াটি আপডেট হচ্ছে না কেন? কারণ আপনি যখন আছে DOM মধ্যে উপাদান মান পরিবর্তন - আপনি যা করতে পারেন console.log()
এর মান অবিলম্বে এটিকে পরিবর্তন করা পর এবং এটা দেখতে যে হয়েছে পরিবর্তন করা হয়েছে (যা শো কেন DVK এর ব্যাখ্যা সঠিক নয়) - ব্রাউজার হ্রাস করার স্ট্যাকের জন্য অপেক্ষা করছে ( on
ফিরে আসার জন্য হ্যান্ডলার ফাংশন) এবং এভাবে বার্তাটি শেষ হয়ে যায়, যাতে শেষ পর্যন্ত এটি আমাদের রূপান্তর পরিচালনার প্রতিক্রিয়া হিসাবে রানটাইম দ্বারা যুক্ত করা বার্তাটি কার্যকর করতে পারে এবং ইউআইতে সেই রূপান্তরকে প্রতিফলিত করতে পারে ।
এটি কারণ আমরা আসলে কোডটি দৌড় শেষ করতে অপেক্ষা করছি। আমরা বলিনি "কেউ এই আনুন এবং তারপরে ফলাফলগুলি দিয়ে এই ফাংশনটি কল করুন, ধন্যবাদ, এবং এখন আমি এতটা ইমাম রিটার্ন সম্পন্ন করেছি, এখনই যাই করুক" যেমনটি আমরা সাধারণত আমাদের ইভেন্ট ভিত্তিক অ্যাসিঙ্ক্রোনাস জাভাস্ক্রিপ্ট দিয়ে করি। আমরা একটি ইভেন্ট ইভেন্ট হ্যান্ডলার ফাংশন প্রবেশ করি, আমরা একটি ডিওএম উপাদান আপডেট করি, আমরা অন্য ফাংশনটি কল করি, অন্য ফাংশনটি দীর্ঘ সময় ধরে কাজ করে এবং তারপরে ফিরে আসে, তারপরে আমরা একই ডিওএম উপাদানটি আপডেট করি এবং তারপরে আমরা কার্যকরভাবে খালি হয়ে প্রাথমিক ফাংশন থেকে ফিরে আসি স্ট্যাক এবং তারপরে ব্রাউজারটি কাতারে পরবর্তী বার্তাটি পেতে পারে, যা খুব ভালভাবে একটি অভ্যন্তরীণ "অন-ডোম-মিউটেশন" টাইপ ইভেন্টটি ট্রিগার করে আমাদের দ্বারা উত্পন্ন একটি বার্তা হতে পারে।
বর্তমানে সম্পাদনকারী ফ্রেমটি শেষ না হওয়া অবধি ব্রাউজার ইউআই (বা নির্বাচন না করা) আপডেট করতে পারে না (ফাংশনটি ফিরে এসেছে)। ব্যক্তিগতভাবে, আমি মনে করি এটি সীমাবদ্ধতার চেয়ে ডিজাইনের মাধ্যমে।
setTimeout
জিনিসটি তখন কাজ করে কেন ? এটি এটি করে, কারণ এটি কার্যকরভাবে দীর্ঘকালীন ক্রিয়াকলাপের কলটিকে নিজের ফ্রেম থেকে সরিয়ে দেয়, window
প্রসঙ্গে পরে এটি সম্পাদন করার সময়সূচী দেয় , যাতে এটি নিজেই তত্ক্ষণাত্ ফিরে আসতে পারে এবং মেসেজের কাতারে অন্য বার্তাগুলি প্রক্রিয়া করতে দেয়। এবং ধারণাটিটি হ'ল যে ইউআই "অন আপডেট" বার্তাটি জাভাস্ক্রিপ্টে ডিওমে টেক্সট পরিবর্তন করার সময় আমাদের দ্বারা ট্রিগার করা হয়েছিল, দীর্ঘকাল ধরে চলমান ফাংশনের জন্য সাইন করা বার্তার আগে এখন এগিয়ে যায়, যাতে আমরা ব্লক করার আগে ইউআই আপডেট হয় অনেকক্ষণ ধরে.
দ্রষ্টব্য যে) দীর্ঘকাল ধরে চলমান ফাংশনটি চালিত হওয়ার পরেও সমস্ত কিছু অবরুদ্ধ করে রাখে এবং খ) আপনার গ্যারান্টিযুক্ত নেই যে ইউআই আপডেটটি বার্তার কাতারে আসলে এটির আগে। আমার জুন 2018 এর ক্রোম ব্রাউজারে, 0
ফিডল যে সমস্যাটি দেখায় - 10 এর দ্বারা একটি মান "ঠিক" করে না। আমি আসলে এটিকে কিছুটা দমিয়ে রেখেছি, কারণ ইউআই আপডেট বার্তাটি তার আগেই সারিবদ্ধ হওয়া উচিত বলে আমার কাছে যৌক্তিক মনে হয়, কারণ "পরে" চালানোর জন্য দীর্ঘস্থায়ী ফাংশন নির্ধারণের আগে এর ট্রিগারটি কার্যকর করা হয়। তবে সম্ভবত ভি 8 ইঞ্জিনে কিছু অপ্টিমাইজেশন রয়েছে যা হস্তক্ষেপ করতে পারে বা আমার বোঝার মধ্যে কেবল অভাব রয়েছে।
ঠিক আছে, তাহলে ব্যবহারে সমস্যা setTimeout
কী, এবং এই বিশেষ কেসের জন্য আরও ভাল সমাধান কী?
প্রথমত, এই জাতীয় setTimeout
ইভেন্ট হ্যান্ডলারটি ব্যবহার করে অন্য সমস্যাটি দূর করার চেষ্টা করতে সমস্যাটি অন্যান্য কোডের সাথে বিশৃঙ্খলাবদ্ধ। এখানে আমার কাজ থেকে একটি বাস্তব জীবনের উদাহরণ:
সহকর্মী, ইভেন্ট লুপ সম্পর্কে ভুল-বোধগম্যভাবে বোঝার জন্য, জাভাস্ক্রিপ্টটির রেন্ডারিংয়ের জন্য কিছু টেম্পলেট রেন্ডারিং কোড ব্যবহার করে "থ্রেড" করার চেষ্টা করেছিলেন setTimeout 0
। তিনি আর জিজ্ঞাসা করার জন্য এখানে নেই, তবে আমি অনুমান করতে পারি যে সম্ভবত তিনি রেন্ডারিং গতি (যা ফাংশনগুলির প্রত্যাবর্তন নীতি হবে) মাপার জন্য টাইমারগুলি সন্নিবেশ করিয়েছিলেন এবং দেখেছেন যে এই পদ্ধতির সাহায্যে এই ফাংশনটি থেকে ঝাপটায় দ্রুত প্রতিক্রিয়া দেখাবে।
প্রথম সমস্যাটি সুস্পষ্ট; আপনি জাভাস্ক্রিপ্টকে থ্রেড করতে পারবেন না, তাই আপনি অবসন্নতা যুক্ত করার সময় আপনি এখানে কিছুই জিততে পারবেন না। দ্বিতীয়ত, আপনি এখন সম্ভাব্য ইভেন্ট শ্রোতার স্ট্যাক থেকে কোনও টেম্পলেটটির রেন্ডারিংকে কার্যকরভাবে আলাদা করেছেন যে খুব সম্ভবত এটি টেমপ্লেট রেন্ডার করা হবে বলে আশা করতে পারে, যদিও এটি খুব ভালভাবে নাও হতে পারে। সেই ফাংশনের আসল আচরণটি এখন অ-সংজ্ঞাবহ, যেমন ছিল - অজান্তেই - কোনও ফাংশন যা এটি চালায়, বা এর উপর নির্ভর করবে। আপনি শিক্ষিত অনুমান করতে পারেন, তবে আপনি এর আচরণের জন্য সঠিকভাবে কোড করতে পারবেন না।
একটি নতুন ইভেন্ট হ্যান্ডলার লেখার সময় "ফিক্স" যা তার যুক্তি নির্ভর করে তাও ব্যবহার করা উচিত setTimeout 0
। তবে, এটি কোনও সমাধান নয়, এটি বোঝা শক্ত এবং এই জাতীয় কোডের কারণে ত্রুটিগুলি ডিবাগ করা মজাদার নয়। কখনও কখনও কখনও কোনও সমস্যা হয় না, অন্য সময় এটি অবিচ্ছিন্নভাবে ব্যর্থ হয় এবং তারপরে আবার কখনও কখনও প্ল্যাটফর্মের বর্তমান পারফরম্যান্স এবং সেই সময়ে যা ঘটতে পারে তার উপর নির্ভর করে বিক্ষিপ্তভাবে এটি কাজ করে এবং বিরতি দেয়। এই জন্যই আমি ব্যক্তিগতভাবে এই হ্যাক (এটা ব্যবহারের বিরুদ্ধে পরামর্শ চাই হয় , একটি হ্যাক, আর আমরা সবাই জানা উচিত এটা যে) যদি না আপনি সত্যিই জানতে আপনি কি করছেন করছি এবং পরিণতি কী হয়।
তবে এর পরিবর্তে আমরা কী করতে পারি? ঠিক আছে, যেমন রেফারেন্সড এমডিএন নিবন্ধটি পরামর্শ দিয়েছে, হয় কাজটিকে একাধিক বার্তায় বিভক্ত করুন (যদি আপনি পারেন) যাতে সারি করা অন্যান্য বার্তাগুলি আপনার কাজের সাথে ইন্টারলিভড হতে পারে এবং এটি চলাকালীন কার্যকর করা যেতে পারে, বা ওয়েব কর্মী ব্যবহার করতে পারে যা চালাতে পারে আপনার পৃষ্ঠার সাথে মিল রেখে এবং এর গণনাগুলি সম্পন্ন করার পরে ফলাফলগুলি প্রদান করে।
ওহ, এবং আপনি যদি ভাবছেন, "আচ্ছা, আমি কি দীর্ঘকাল ধরে চলমান ফাংশনটিতে এটিকে অবিচ্ছিন্ন করে তুলতে পারি না?", তাহলে না। কলব্যাক এটিকে অবিচ্ছিন্ন করে তোলে না, স্পষ্টভাবে আপনার কলব্যাক কল করার আগে এটি দীর্ঘ-চলমান কোডটি চালাতে হবে।