انٹرویو بعض اوقات، صرف ایک طویل چلانے جاوا اسکرپٹ تقریب انٹرفیس کو منجمد کرنے کے لئے کافی ہے، صارفین کو ناپسندیدہ اور اس بات کا یقین نہیں ہے کہ یہ اپلی کیشن اب بھی کام کر رہا ہے یا منجمد ہے. ایک چھوٹا لیکن طاقتور طریقہ کار پیش کرتا ہے: یہ ایک صارف کو کارکردگی کو وقف کرنے کی اجازت دیتا ہے، براؤزر کو زیادہ اہم کاموں (مثال کے طور پر کلک یا ٹائپنگ) کا انتظام کرنے کا موقع فراہم کرتا ہے، اور پھر وہ جہاں چھوڑ دیا گیا ہے وہاں جاری رکھتا ہے. ، پرانے Workarounds کا تجربہ کریں، اور دیکھیں کہ کس طرح زندگی کو آسان بناتا ہے Prioritized Task Scheduling API کا استعمال کریں زمرہ:پہلے مرحلے( Main Thread scheduler.yield() یہ کیا ہے.Yield() تو، کیا ہے یہ ایک طریقہ ہے کہ انٹرفیس سے نئے یہ طریقہ آپ کو، ایک ڈویلپر کے طور پر، آپ کی جاوا اسکرپٹ کی کارکردگی کو روکنے اور واضح طور پر کنٹرول کو واپس حاصل کرنے کی اجازت دیتا ہے. - تاکہ یہ دیگر اہم کاموں، جیسے صارف کے تعاملات، کلک، ٹائپنگ، وغیرہ کے ساتھ کام کرسکتا ہے، اور اس کے بعد آپ نے چھوڑ دیا جہاں سے کام جاری رکھ سکتا ہے. آپ براؤزر کو کہتے ہیں: scheduler.yield() منصوبہ بندی Prioritized Task Scheduling API کا استعمال کرتے ہوئے Main Thread scheduler.yield() "چلو، ایک سانس لیں، ہم موجودہ کام کو روک دیں اور دیگر نہیں کم یا زیادہ اہم کاموں پر توجہ مرکوز کریں. "چلو، ایک سانس لیں، ہم موجودہ کام کو روک دیں اور دیگر نہیں کم یا زیادہ اہم کاموں پر توجہ مرکوز کریں. یہ آپ کی صفحہ کو زیادہ responsive کرتا ہے، خاص طور پر طویل یا بھاری جاوا اسکرپٹ کاموں کو چلانے کے دوران. - جس میں یہ سب اس کے بارے میں ہے کہ براؤزر صارف کے انٹرویو پر کس طرح تیزی سے جواب دیتا ہے. Next Paint (INP) کے ساتھ بات چیت Terminology میں آپ کو زیادہ گہری ڈوبنے سے پہلے، ہم جلد ہی چند بنیادی اصطلاحات پر جائیں گے جو مضمون میں استعمال کیا جائے گا. Main Thread – یہ مرکزی جگہ ہے جہاں براؤزر اپنے کام کا سب سے زیادہ کام کرتا ہے. یہ rendering، layout، اور آپ کے جاوا اسکرپٹ کوڈ کے سب سے زیادہ چلتا ہے. طویل کام - یہ کسی بھی جاوا اسکرپٹ کام ہے جو بہت طویل عرصے تک، عام طور پر 50 ملیس سیکنڈ سے زیادہ، ماسٹر ٹریڈ کو مصروف رکھتا ہے. Blocking task – Main Thread پر ایک سنکنرن عمل ہے جو براؤزر کو دیگر اہم چیزوں کو پروسیسنگ کرنے سے روکتا ہے، جیسے کلک کے جوابات یا UI کو اپ ڈیٹ کرنا. مسئلہ ہے خوبصورتی کو سمجھنے کے لئے ، آپ کو سب سے پہلے یہ سمجھنے کی ضرورت ہے کہ یہ کس مسئلہ کو حل کرنے کی کوشش کر رہا ہے. جاوا اسکرپٹ ایک ہی ٹرانسمیشن پر چلتا ہے. اس کا مطلب یہ ہے کہ یہ صرف ایک ہی وقت میں ایک چیز کر سکتا ہے. اگر آپ کا کوڈ ٹرانسمیشن پر کام رکھتا ہے تو، باقی سب کچھ - rendering، بٹن کلک، input typing کو انتظار کرنا پڑتا ہے. ایک مثالی دنیا میں، آپ کو ہمیشہ چھوٹے حصوں میں بھاری کاموں کو تقسیم کرنا پڑے گا. لیکن حقیقت خراب ہے. آپ پرانے کوڈ، تیسرے فریق سکرپٹ، یا ناامیدی بھاری کمپیوٹرز کے ساتھ کام کرتے ہیں. اور جب ایسا ہوتا ہے تو، صارفین کو ٹھنڈے صفحات کے ساتھ پکڑا جاتا ہے. scheduler.yield() جاوا اسکرپٹ کے مترادفات ایک فوری اپ ڈیٹ کے طور پر، یہاں ایک مثال دیگرامی ہے کہ JavaScript کاموں کو کیسے پروسیس کرتا ہے - دوسرے الفاظ میں، یہ کس طرح کام کرتا ہے. میں یقین کرتا ہوں کہ آپ میں سے بہت سے پہلے اس طرح کے ڈرامے دیکھ چکے ہیں - کام کی چیلنجوں، واقعات کی چیلنج، کال سٹاک. یہ کامل نہیں ہے، لیکن یہ آپ کو بڑی تصویر دیتا ہے. JavaScript Execution Model ہم بنیادی خیالات کے ذریعے قدم بعد قدم چلتے ہیں: تمام سنکنرن کوڈ براہ راست کال سٹاک پر جاتا ہے اور لائن کے بعد چلتا ہے، فہرست کے بعد کام کرتا ہے. یہ LIFO اصول کی پیروی کرتا ہے - آخری میں، سب سے پہلے باہر. جاوا اسکرپٹ ایک ٹرانسمیشن میں چلتا ہے، جس کا مطلب ہے کہ یہ ایک وقت میں صرف ایک چیز کر سکتا ہے. Asynchronous آپریشنز (مثال کے طور پر setTimeout، fetch) Main Thread کے باہر کام کرتے ہیں - ویب ایپائیز کی طرف سے (مزید براؤزر یا ماحول کی طرف سے فراہم کی جاتی ہے). ایک بار جب وہ کر رہے ہیں، وہ براہ راست Call Stack میں واپس نہیں جا رہے ہیں. اس کے بجائے، ان کے callbacks کو چیلنج کیا جاتا ہے - either in the microtasks queue (مثال کے طور پر، Promise.then، queueMicrotask) یا macrotasks queue (مثال کے طور پر setTimeout، setInterval). جب Call Stack خالی ہے تو، Event Loop میکروٹاسک کی چیلنج کو چیک کرتا ہے اور تمام میکروٹاسک کو ایک کے بعد ایک مرتبہ چلاتا ہے. صرف اس کے بعد، یہ چیلنج سے ایک میکرو کام لیتا ہے اور اسے چلتا ہے. اگر پروسیسنگ کے دوران نئے مائیکروٹاسکٹس شامل ہوتے ہیں تو، وہ اگلے میکروٹاسکٹ سے پہلے چلائے جاتے ہیں. یہ لنک جاری رکھتا ہے: تمام مائیکروٹاسکشن → ایک میکروٹاسکشن → دوبارہ کریں. نئے سکرپٹ کوڈ کال سٹاک میں آتا ہے جب نئے کام آتے ہیں، جیسے ایک صارف کو ایک بٹن پر کلک کرتے ہیں، ایک نیا سکرپٹ چل رہا ہے، یا جب ایک مائکروٹاسک یا میکروٹاسک اس کی کالنگ چلتا ہے. یہ ایک بہت مختصر اور سطحی وضاحت ہے، صرف آپ کو یاد دلانے کے لئے کہ یہ کیسے کام کرتا ہے. مسئلہ کی وضاحت اب جب آپ کو آپ کی سمجھ کو تازہ کر دیا ہے کہ کس طرح جاوا اسکرپٹ کاموں کو انجام دیتا ہے، ہم اس ماڈل کے ساتھ آتا ہے کہ حقیقی مسئلہ پر ایک نظر ڈالیں. مسئلہ سادہ ہے: جب ایک کام بنیادی ٹرانسمیشن پر بہت طویل وقت لگتا ہے، تو یہ سب کچھ بند کرتا ہے - صارف کے تعاملات، رینجنگ اپ ڈیٹس، اور انیمیشنز. یہ UI کو ٹھنڈا کرتا ہے اور کم ردعمل. واضح پہلا خیال ہوسکتا ہے: "ہاں، صرف طویل یا سنگین افعال نہیں لکھتے ہیں، اور یہ وہی ہے. مسئلہ حل کیا گیا ہے!" اور جی ہاں، یہ سچ ہے - ایک مثالی دنیا میں، آپ ہمیشہ بڑے کوڈ کو چھوٹے حصوں میں تقسیم کریں، سب کچھ بہتر کریں، اور بنیادی ٹرانسمیشن کو اس کے لئے، ہم ایک تقریب بنائیں گے جس کا نام جو مخصوص مدت کے لئے بنیادی ٹرانسمیشن کے لئے ایک بلاکنگ کام کے طور پر کام کرتا ہے.The function simulates this kind of "heavy" calculation on each element of the array. blockingTask() بدقسمتی سے کوڈ بلاکس لائنوں کی تعداد ظاہر نہیں کرتے ہیں۔ میری وضاحتوں میں، میں بعض اوقات مخصوص لائنوں کا ذکر کرتا ہوں (مثال کے طور پر، "ریڈ 5 X کرتا ہے"). بدقسمتی سے کوڈ بلاکس لائنوں کی تعداد ظاہر نہیں کرتے ہیں۔ میری وضاحتوں میں، میں بعض اوقات مخصوص لائنوں کا ذکر کرتا ہوں (مثال کے طور پر، "ریڈ 5 X کرتا ہے"). function blockingTask(ms = 10) { const arr = []; const start = performance.now(); while (performance.now() - start < ms) { // Perform pointless computation to block the CPU. arr.unshift(Math.sqrt(Math.random())); } return arr; } اس کے بارے میں کوئی فینسی نہیں ہے، یہاں یہ سب کچھ ہے: یہ ایک اقسام کو قبول کرتا ہے - ملیس سیکنڈ کی تعداد. یہ کم از کم وقت ہے جس میں افعال چلائے گا، اس طرح بنیادی ٹریڈ پر قبضہ کرتا ہے. یہ ایک خالی آرڈر پیدا کرتا ہے. یہ ایک ابتدائی وقت (مثال کے طور پر ایک موجودہ وقت) پیدا کرتا ہے. اس کے بعد کچھ عرصے تک اس وقت تک چلتا ہے جب تک کہ مقررہ وقت گزر چکا ہے. لنک کے اندر، یہ صرف لامحدود، غیر قابل ذکر محاسبات کرتا ہے کہ لوڈ کی نمائش کرتا ہے. آخر میں، یہ حساب کے نتائج کی واپسی کرتا ہے. فہرست کچھ بھی مفید نہیں کرتا، لیکن یہ ایک حقیقی دنیا میں سنگین لوڈ کے اسکرین کی نمائش کرتا ہے. ایک عام صورت حال کی تصور کریں جہاں آپ کو ڈیٹا کی ایک سیریز کے ذریعے چلا جانا اور ہر اشیاء پر یہ مشکل کام لاگو کرنے کی ضرورت ہے. ایسا کرنے کے لئے، ہم ایک کام کرتا ہے: heavyWork() function heavyWork () { const data = Array.from({ length: 200 }, (_, i) => i) const result = [] for (let i = 0; i < data.length; i++) { result.push(blockingTask(10)) } return result; } جس میں مندرجہ ذیل ہوتا ہے: لائن 2 پر، یہ 200 اشیاء کی ایک سیریز پیدا کرتا ہے، صرف 0 سے 199 تک کے اعداد و شمار. اس کے بعد، پروسیسنگ کے اعداد و شمار کو ذخیرہ کرنے کے لئے ایک نیا خالی "نتائج" اعداد و شمار پیدا ہوتا ہے. لائن 5 ایک لنک کا اعلان کرتا ہے جو اعداد و شمار کی پوری لمبائی کے ذریعے چلا جاتا ہے. لنک کے اندر، ہم BlockingTask() تقریب کو چلاتے ہیں، ہر عنصر کے لئے 10 ملیس سیکنڈ کے کام کی نمائش کرتے ہیں، اور نتیجہ "نتائج" ماریہ میں شامل کیا جاتا ہے. ایک بار پھر، میں آپ کو یاد رکھنا چاہتا ہوں کہ، ڈیمو کے لئے، BlockingTask() تقریب کسی بھی سمینٹک لوڈ نہیں رکھتی ہے. یہ صرف کچھ تخلیقی، وسائل کی شدت سے کام کرتا ہے. حقیقی دنیا میں، یہ ایک ماریہ عنصر کے کچھ کام کی شدت سے پروسیسنگ ہو سکتا ہے. آخر میں، یہ پیدا ہونے والے آرڈر واپس کرتا ہے. صرف 10 ملیس سیکنڈ فی عنصر، اور صرف 200 عنصر - لیکن ایک ساتھ، وہ 2 مکمل سیکنڈ کے لئے بنیادی ٹریڈ کو بلاک کرتے ہیں. مسئلہ کا مظاہرہ یہ ابھی تک ایک مکمل ڈیمو نہیں ہے - آپ کو مسئلہ کو واضح طور پر دیکھنے میں مدد کرنے کے لئے یہ ایک سادہ بصری طور پر سوچیں. یہاں آپ کیا دیکھتے ہیں: بائیں ونڈو، "Configuration" کے عنوان سے، آپ کو بنیادی ٹرانسمیشن بلاکنگ کو چالو کرنے اور بند کرنے کی اجازت دیتا ہے - جس کا مطلب ہے کہ بلاکنگTask() فورم واقعی چل رہا ہے. "Heavy Task" نامی ونڈو heavyWork() تقریب کو چلاتا ہے. یہ وہی ہے جو ہر عنصر پر blockingTask() کا استعمال کرتے ہوئے ایک سیریز کو پروسیسنگ کرتا ہے اگر بنیادی ٹرانسمیشن بلاک کرنے کی اجازت ہے. اور "Logger" کے عنوان پر ونڈو صرف کنسل میں موجودہ وقت کو لاگ ان کرتا ہے، ملیس سیکنڈ بھی شامل ہے. دیکھیں کہ کیا ہوتا ہے جب بلاکنگ غیر فعال ہے، لہذا کام بہت آسان ہیں. یہ صرف 200 عناصر کی ایک سیریز پر ایک چیلنج ہے، کسی بھی پیچیدہ محاسبات کے بغیر. Main Thread آپ کیا دیکھتے ہیں: صارف "OK" بٹن پر کلک کرتا ہے - heavyWork() افعال چلتا ہے، اور فوری طور پر واپس آتا ہے. اس کے بعد، صارف "لوگ" بٹن پر تین بار کلک کرتا ہے، کنسول میں موجودہ وقت کو لاگ ان کرنے کے لئے - وقت سٹامز فوری طور پر ظاہر ہوتے ہیں، وقت میں ایک چھوٹا سا فرق کے ساتھ. صارف دوبارہ heavyWork() تقریب کو چلتا ہے، اور پھر فوری جواب. آخر میں، صارف دو ونڈوز بند کرتا ہے، جو اصل میں صرف DOM سے ان عناصر کو ہٹا دیتا ہے. اس صورت میں، سب کچھ تیزی سے اور ردعمل محسوس ہوتا ہے. براؤزر کے ساتھ بات چیت کا انتظام کرنے میں کوئی مشکل نہیں ہے، کیونکہ بنیادی ٹریڈ مفت رہتا ہے. کام تقریبا فوری طور پر اور مطابقت سے کیا جاتا ہے. اب، ہم اس کی اجازت دیتے ہیں ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ،جیسے ، آپ کو صرف 10 ملی سیکنڈ کی تاخیر کے ساتھ فون کیا جائے گا. Main Thread blockingTask() اور اب آپ دیکھ سکتے ہیں کہ UI اجزاء کے ساتھ صارف کے تعامل کو کم سست ہو گیا ہے، UI ٹھنڈا ہوا ہے. صارف "OK" بٹن پر کلک کرتا ہے، اس طرح heavyWork() تقریب کو شروع کرتا ہے. اور پہلی تاخیر جو ہوتا ہے یہ ہے کہ "OK" بٹن بصری طور پر دباؤ میں رہتا ہے. کیوں؟ کیونکہ براؤزر دوبارہ پینٹ نہیں کرسکتا ہے جبکہ heavyWork() اب بھی بنیادی ٹریڈ کو بلاک کر رہا ہے. اور یہ سمجھنے کے لئے اہم ہے کہ ہم صرف موجودہ کام کے بارے میں نہیں بلکہ کلک کٹ کے بارے میں بات کر رہے ہیں. اس وقت کے دوران، صارف "لوگ" بٹن پر چار بار کلک کرتا ہے - کچھ بھی نہیں ہوتا. کلکنگ کو رجسٹر کیا جاتا ہے اور ان کے ٹرانسمیٹرز چیلنج میں شامل کیے جاتے ہیں، لیکن براؤزر رد عمل نہیں کر سکتے ہیں. صرف heavyWork() ختم ہونے کے بعد آپ کنسول کے پیداوار کو دیکھتے ہیں: سب سے پہلے heavyWork() نتیجہ، پھر چار Timestamps - سب کو ایک بیٹری میں پرنٹ کیا جاتا ہے. اور صرف اس کے بعد، "OK" بٹن اس کی حالت تبدیل کر دیا اور غیر پرنٹ کیا گیا. اس کے بعد، صارف دوبارہ "OK" بٹن پر کلک کرتا ہے. اسی طریقہ کار - پکڑو بٹن. پھر، جب heavyWork() کام چل رہا ہے، وہ "X" آئکن پر تین بار کلک کرکے ایک ونڈو بند کرنے کی کوشش کرتا ہے. دوبارہ، کوئی بصری جواب نہیں. اور آخر میں، ایک اور کوشش heavyWork() کو چلانے اور آخری ونڈو بند کرنے کے لئے. یہ کیا دکھاتا ہے؟ یہ سادہ ڈیمو دکھاتا ہے کہ کتنی دیر تک کاموں کو براؤزر کے صارفین کے کارروائیوں کا جواب دینے کی صلاحیت کو روکتا ہے. اگرچہ ہر بلاکنگ کال صرف 10 ملیس سیکنڈ لگتا ہے، ان میں سے 200 کو ایک دوسرے کے ساتھ جھاڑنے کے نتیجے میں 2 سیکنڈ منجمد ہو جاتا ہے. صارف بٹن کے ساتھ بات چیت نہیں کرسکتا، انٹرفیس دوبارہ رنگ نہیں کرتا. واقعات کو چیلنج کیا جاتا ہے، لیکن کال سٹاک کو صاف کرنے تک پروسیسنگ نہیں کیا جاتا ہے. یہ صرف ایک کارکردگی کا مسئلہ نہیں ہے - یہ ایک صارف کے تجربے کا مسئلہ ہے. مسئلہ کا حل اب جب آپ مسئلہ کو سمجھتے ہیں تو، ہم ممکنہ حلوں کے بارے میں بات کریں. یقینی طور پر، سب سے بہترین حکمت عملی پہلے سے طویل کاموں سے بچنا ہے، کوڈ کو مؤثر بنانا اور چیزوں کو پہلے سے ہی بند کرنا ہے. لیکن، جیسا کہ آپ نے دیکھا ہے، چیزیں ہوتی ہیں. چاہے یہ پرانے کوڈ ہے، غیر متوقع حساب، یا صرف بہتر بنانے کے لئے کافی وقت نہیں ہے، کبھی کبھی، آپ کو اس سے نمٹنے کی ضرورت ہے. اس کے بعد، مختلف حل اور ٹریکوں کو ردعمل کو بہتر بنانے کے لئے تیار کیا گیا ہے. لیکن ان سب کے پیچھے بنیادی خیال - اور پیچھے اس کے علاوہ - یہ بہت سادہ ہے: Prioritized Task Scheduling API scheduler.yield() ایک کام کو چھوٹے ٹکڑے یا کہا جاتا ٹکڑے میں تقسیم کریں. اور بار بار، براؤزر کو سانس لینے کی اجازت دینے کے لئے وقف کریں. دوسرے الفاظ میں، آپ اہم ٹرانسمیشن کو زیادہ فوری کاموں کو چلانے کا موقع دیتے ہیں، جیسے صارف کے تعاملات یا اپ ڈیٹ rendering، اور پھر آپ اپنے کام کو ختم کرنے کے لئے واپس آتے ہیں. یہاں یہ ہے کہ کس طرح کے خیالات فہرست pseudocode کی طرح لگتا ہے: heavyWork() function heavyWork() { // Do heavy work... /** * Take a breather! * Yield the execution to the Main Thread... * */ // Continue to do heavy work... } یہاں کیا ہو رہا ہے: آپ اپنے کام کا ایک ٹکڑا چلتے ہیں. اس کے بعد، آپ وقف کر رہے ہیں، براؤزر کو دیگر اعلی ترجیحات کے کاموں (مثلا UI اپ ڈیٹ) کا انتظام کرنے کی اجازت دیتا ہے. کام کو وہاں سے جاری رکھیں جہاں وہ چھوڑ دیا گیا ہے. پرانے مسائل کا حل کرنے کا طریقہ پہلے کے ساتھ آیا، طویل مدتی بلاکنگ کاموں سے نمٹنے کے لئے سب سے زیادہ عام ٹریک استعمال کرنا تھا ایک 0 (نور) تاخیر کے ساتھ اس کو کال کرتے ہوئے، آپ اس کے کال بیک اپ کام کے اختتام پر شامل کرتے ہیں دوسری طرف، آپ براؤزر کو بتاتے ہیں کہ: scheduler.yield() setTimeout() macrotasks "اس تھوڑی سی کوڈ کو بعد میں چلائیں، جب آپ نے باقی سب کا کام کیا ہے." "اس تھوڑی سی کوڈ کو بعد میں چلائیں، جب آپ نے باقی سب کا کام کیا ہے." اس طرح آپ بنیادی ٹریڈ کو سخت کام کے ٹکڑوں کے درمیان ایک مختصر سانس دے سکتے ہیں. یہاں یہ ہے کہ اپ ڈیٹ کیا ہے یہ کام اس طریقہ کار کا استعمال کرتے ہوئے ہوسکتا ہے: heavyWork() async function heavyWork() { // Yield to Main Thread to avoid UI blocking before heavy work await new Promise(resolve => setTimeout(resolve, 0)) const data = Array.from({ length: 200 }, (_, i) => i) const result = [] // Interval at which execution will be yielded to the main thread (approx. ~ 25%). const yieldInterval = Math.ceil(data.length / 4) for (let i = 0; i < data.length; i++) { // Yield control to Main Thread to update UI and handle other tasks. if (i % yieldInterval === 0) { await new Promise(resolve => setTimeout(resolve, 0)) } result.push(threadBlockingEnabled ? blockingTask(10) : data[i]) } return result } یہاں جو کچھ ہو رہا ہے اس کو تقسیم کریں: خط 3: ایک وعدہ پیدا کیا جاتا ہے اور اس کے عملے کو فوری طور پر چلتا ہے، ایک setTimeout() کی منصوبہ بندی کے ساتھ صفر تاخیر کے ساتھ. Timeout کا کال بیک (جو وعدہ حل کرتا ہے) میکروٹاسک کی رکاوٹ کے اختتام تک شامل کیا جاتا ہے. انتظار کی وجہ سے، باقی async فیکچر کو روک دیا جاتا ہے. تکنیکی طور پر، یہ مسلسل microtask کی رکاوٹ میں شامل کیا جاتا ہے، وعدہ حل کرنے کے لئے وعدہ کا انتظار کرتا ہے. جاوا اسکرپٹ انجن کال Stack کو چیک کرتا ہے - جب یہ خالی ہے، واقعہ لوپ میں کلک کرتا ہے. سب سے پہلے، یہ میکروٹاسک کی رکاوٹ کو دیکھتا ہے - لیکن وعدہ کو حل نہیں کیا گیا ہے کیونکہ یہ ابھی تک حل نہیں کیا گیا ہے، لائن 9: ہم شمار کرتے ہیں کہ ہم کس طرح سے اکثر چاہتے ہیں کہ ہم کام کے تقریبا ہر 25٪ کے لئے بنیادی تھریڈ کو منافع بخش کریں. لائنوں 13-15: لنک کے اندر، اگر yielding interval کے لئے شرط پورا ہوتا ہے تو، execution main thread پر منتقل ہوتا ہے، یعنی، setTimeout() تکنیک کو دوبارہ کیا جاتا ہے، براؤزر پروسیسز صارف کے تعاملات کی اجازت دیتا ہے یا انٹرفیس کو دوبارہ ڈرائنگ. بنیادی طور پر، یہ نقطہ نظر کام کرتا ہے - یہ نسبتا سادہ ہے اور ردعمل کو بہتر بناتا ہے. لیکن توازن ہیں. یہ درست منصوبہ بندی کے لئے تعمیر نہیں کیا گیا ہے. یہ میکروٹاسک کی چیلنج کے آخر میں کام رکھتا ہے، اور اس چیلنج میں پہلے سے ہی کچھ بھی آپ کی جاری رکھنے میں تاخیر کرسکتا ہے. setTimeout() مثال کے طور پر، ہم کہتے ہیں کہ صفحہ کا کچھ اور حصہ استعمال کرتا ہے منظم طور پر کام کرنے کے لئے: setInterval() setInterval(() => { /* Another heavy work... */ }) async function heavyWork() { // Yield to Main Thread to avoid UI blocking before heavy work await new Promise(resolve => setTimeout(resolve, 0)) const data = Array.from({ length: 200 }, (_, i) => i) const result = [] // Interval at which execution will be yielded to the main thread (approx. ~ 25%). const yieldInterval = Math.ceil(data.length / 4) for (let i = 0; i < data.length; i++) { // Yield control to Main Thread to update UI and handle other tasks. if (i % yieldInterval === 0) { await new Promise((resolve, reject) => setTimeout(resolve, 0)) } result.push(threadBlockingEnabled ? blockingTask(10) : data[i]) } return result } اب آپ کا اپنا کام - اگلے ٹکڑا فہرست – ان intervall callbacks میں سے ایک یا زیادہ کی طرف سے تاخیر ہوسکتا ہے. براؤزر صرف خط میں اگلا ہے جو کچھ بھی چلتا ہے، اور آپ حکم کو کنٹرول نہیں کرتے ہیں. آپ کو واپسی کی اجازت دیتا ہے، آپ کو یہ معلوم نہیں ہے کہ آپ کو کنٹرول واپس کب ملے گا. heavyWork() setTimeout() اس طرح کے مسائل کو حل کرنے کے لئے کچھ طریقے ہیں، یہ ممکن ہے کہ فائل، جس سے آپ کو اگلے دوبارہ پینٹنگ سے پہلے کام کی منصوبہ بندی کرنے کی اجازت دیتا ہے. اس کے علاوہ، اس طرح کے منفی اثرات ہیں، یا یہ ایک براؤزر خالی وقت کے دوران آپ کا کوڈ چلتا ہے. یہ بالکل ایک متبادل نہیں ہے، لیکن پس منظر کے لئے اچھا ہے، کم اہم کام، جس میں اہم ٹرانسمیشن کو زیادہ اہم کاموں کے لئے مفت بنانے میں مدد ملتی ہے. عام طور پر، ہم اس طرح کے مسائل کو حل کرنے اور روکنے کے لئے دیگر حکمت عملی پر بحث کرسکتے ہیں. تاہم، موضوع پر رہنے کے لئے، ہم آگے بڑھیں اور دیکھیں کہ کیا ہے میز پر لے آؤ requestAnimationFrame() setTimeout() requestIdleCallback() scheduler.yield() ایڈجسٹ کریں ( – ایک جدید طریقہ ہے کہ عمل کو روکنے کے لئے، اور بنیادی تھریڈ کو کنٹرول فراہم کرتا ہے، جو براؤزر کو کسی بھی منتظر اعلی ترجیحات کے کام کو انجام دینے کی اجازت دیتا ہے، اور پھر وہاں سے عمل جاری رکھتا ہے جہاں سے یہ روک دیا گیا تھا. ایک بیان حاصل کیا جاتا ہے، جس میں یہ بلایا گیا تھا اس کے موجودہ فائل کے عمل کو متوقف کیا جاتا ہے، اور اس کے نتیجے میں موجودہ کام کو توڑنے یا روکنے کے لئے بنیادی ٹرانسمیشن کو کنٹرول دیتا ہے.The continuation of the function, that is, the execution of the remainder of it, from where it left off, is a separate, newly scheduled microtask in the Event Loop. scheduler.yield() await scheduler.yield() اس کی خوبصورتی اس کے بعد جاری ہونے والے آگے بڑھنے کی منصوبہ بندی کی گئی ہے اور اس کے لئے تیار ہے کسی بھی غیر ضروری کام کے لئے جو چیلنج کیا گیا ہے. نقطہ نظر یہ ہے کہ کے ساتھ ، یہ جاریات عام طور پر کسی بھی نئے کاموں کے بعد چلتے ہیں جو پہلے سے ہی چیلنج کیے گئے ہیں، ممکنہ طور پر بنیادی ٹرانسمیشن اور ان کی تکمیل کے درمیان طویل تاخیر کا سبب بناتے ہیں. scheduler.yield() scheduler.yield() BEFORE setTimeout() setTimeout() مندرجہ ذیل ڈراگراف یہ دکھاتا ہے کہ تین طریقوں کو عملی طور پر کس طرح موازنہ کیا جاتا ہے: In the first example, without yielding to the main thread: At first, the long " " runs uninterrupted, blocking the main thread and UI accordingly. Then, a user event is processed – a button click triggered during the execution of " ". And finally, " " is executed – callback scheduled earlier or during the execution of the long task. Task 1 Task 1 Task 2 setTimeout() In the second example, using as a yielding to the main thread: The execution queue is different. At first, the long " " runs. Then, when the yield to the main thread happens, " " pauses to let the browser breathe, and the button click is processed. But after the button click is processed, the callback will be executed first, which could have been scheduled in advance or during the execution of " ". And finally, only after that, the continuation of " " will be executed. setTimeout() Task 1 Task 1 setTimeout() Task 1 Task 1 In the last example, using : After the long " " has been paused and the user click event has been processed, then the continuation of " " is prioritized and runs before any queued tasks. scheduler.yield() Task 1 Task 1 setTimeout() In summary, is a more intelligent and predictable way to give the main thread breathing room. It avoids the risk of your code being pushed too far back in the queue and helps maintain performance and responsiveness, especially in complex applications. scheduler.yield() ترجیحات لہذا، کیا سلوک میں اس طرح کے فرق کا سبب بناتا ہے؟ یہ سب ترجیحات کے بارے میں ہے! ڈویلپرز کے طور پر، ہم عام طور پر ترجیحات کے لحاظ سے واقعات چیلنج میں کاموں کو انجام دینے کی ترتیب کے بارے میں نہیں سوچتے ہیں. اور لیکن اگر آپ زیادہ گہری نظر ڈالیں تو، آپ دیکھیں گے کہ کھیل میں غیر متوقع ترجیحات بھی ہیں. مثال کے طور پر، ایک بٹن کلک ڈرائیور، صارف کی کارروائی کی طرف سے چلایا جاتا ہے، عام طور پر ایک سے پہلے چلائے گا. callback, even though both are جیسا کہ پہلے ذکر کیا گیا ہے، اس کا حصہ ہے – ایک وسیع اور خصوصیات میں امیر انٹرفیس جو اپنی منفرد مکمل بحث کے قابل ہے اور واضح طور پر اس بات کی حد سے باہر ہے. تاہم، اس کے اہم خصوصیات میں سے ایک کا ذکر کرنا ضروری ہے: ایک واضح کام کی ترجیحات کے ماڈل کی داخلہ. Prioritized Task Scheduling API صرف ان ترجیحات کو واضح بناتا ہے، اس سے یہ آسان بناتا ہے کہ کون سا کام سب سے پہلے چلایا جائے گا، اور اگر ضروری ہو تو عمل کی ترجیحات کو تبدیل کرنے کے لئے ترجیحات کو اپ ڈیٹ کرنے کی اجازت دیتا ہے. یہاں اس کی اہم ترجیحات کی سطحوں کی ایک فوری نظر ہے: microtasks macrotasks setTimeout() macrotasks scheduler.yield() Prioritized Task Scheduling API "user-blocking" - سب سے زیادہ ترجیحات کے کاموں جو براہ راست صارف کے تعامل کو متاثر کرتے ہیں، جیسے کلکنگ، ٹپ، اور اہم UI آپریشنز کا انتظام. "User-visible" - کام جو UI کی دیکھ بھال یا مواد کو متاثر کرتے ہیں، لیکن فوری داخلے کے لئے اہم نہیں ہیں. "پہلے" - کام جو فوری نہیں ہیں، اور موجودہ صارف کے تجربے کو متاثر کرنے کے بغیر محفوظ طریقے سے ہٹا دیا جا سکتا ہے، اور صارف کے لئے ظاہر نہیں ہیں. غیر معمولی طور پر، has a " اولیٰ ۔ ۔ ۔ ۔ ۔ ۔ دکھائی دے اس طریقہ کار، اس سے اوپر سے ایک مخصوص ترجیح کے ساتھ کاموں کی منصوبہ بندی کرنے کے لئے ڈیزائن کیا گیا ہے. اگرچہ یہ اس طریقہ کار کے بارے میں تفصیلات میں نہیں جائے گا یہاں، یہ ذکر کرنے کے قابل ہے کہ اگر کے اندر سے منصوبہ بندی کیا گیا تھا وہ اپنی ترجیحات کا وارث ہے. scheduler.yield() user-visible Prioritized Task Scheduling API postTask() scheduler.yield() postTask() کس طرح scheduler.yield() کا استعمال کرتے ہوئے ایک بار جب آپ سمجھتے ہیں کہ یہ سب کیسے کام کرتا ہے - کاموں کے اقسام، لمبی بلاکنگ آپریشنز کی وجہ سے مسئلہ، اور ترجیحات، استعمال یہ آسان بن جاتا ہے. لیکن یہ حکمت عملی اور احتیاط کے ساتھ استعمال کیا جانا چاہئے. یہاں ایک اپ ڈیٹ ورژن ہے استعمال کرنے کا کام اب، اس کے بجائے آپ کو صرف کال کرنے کی ضرورت ہے اور باقی حصہ تبدیل نہیں ہوا. scheduler.yield() heavyWork() scheduler.yield() setTimeout() await scheduler.yield() async function heavyWork() { // Yield to Main Thread to avoid UI blocking before heavy work await scheduler.yield() const data = Array.from({ length: 200 }, (_, i) => i) const result = [] // Interval at which execution will be yielded to the main thread (approx. ~ 25%). const yieldInterval = Math.ceil(data.length / 4) for (let i = 0; i < data.length; i++) { // Yield control to Main Thread to update UI and handle other tasks. if (i % yieldInterval === 0) { await scheduler.yield() } result.push(threadBlockingEnabled ? blockingTask(10) : data[i]) } return result } جب ایک صارف شروع کرتا ہے استعمال کرنے کا کام ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ،ہوگے ، " بٹن نہیں پکڑتا ہے، اور دوسرا، صارف واقعات پر کلک کرتا ہے " بٹن کو کامیاب طریقے سے پروسیسنگ کیا جاتا ہے، جو صارف کے صفحے کے ساتھ بات چیت کو روک نہیں دیتا. heavyWork() scheduler.yield() OK Log یہ ہے، سب سے پہلے، اس کام کو شروع کیا گیا تھا، اور بٹن کو پکڑنے کے بغیر دوبارہ ادا کیا گیا تھا. جبکہ یہ سنگین کام کیا جا رہا تھا، صارف نے " " بٹن.ان واقعات کو کامیاب طریقے سے پروسیس کیا گیا تھا، اور اعداد و شمار کنسول پر پرنٹ کیا گیا تھا. کام جاری کیا گیا تھا، اور اس کا آخری نتیجہ کنسول پر پرنٹ کیا گیا تھا. مکمل کرنے کے بعد، صارف نے " مختصر طور پر، آپ اپنے براؤزر کو صرف ایک لائن کے ساتھ ایک لمحہ دے سکتے ہیں. heavyWork() Log heavyWork() Log ڈیمو کام کی وضاحت اب جب آپ نے نظریہ کا تجربہ کیا ہے تو، ہم ایک حقیقی کام کرنے والے ڈیمو پر نظر ڈالیں. یہ ایک متحرک بینکنگ ایپلی کیشن ہے. یقینی طور پر، یہ تخیل اور سادہ ہے، لیکن یہ آپ کو سمجھنے میں مدد کرنے کے لئے کافی حقیقی دنیا کی پیچیدگی کو پکڑتا ہے کہ کس طرح بنیادی تھریڈ کو بلاک کرنے سے انٹرایکٹی پر اثر انداز ہوتا ہے، اور کس طرح مدد کر سکتے ہیں scheduler.yield() یہاں یہ ہے کہ صارف انٹرفیس میں کیا دیکھتا ہے: – By default, the account balance is hidden behind a placeholder of asterisks. This is a familiar pattern in real banking apps, where sensitive information is hidden unless explicitly revealed by the user. A button labeled " " toggles visibility. Balance section Show balance – A visual representation of a bank card, shown front side by default, where some details are displayed: card type in the top left corner, last 4 digits of the card, the cardholder's name, and payment system, at the bottom right corner of the card. There are two buttons to the right of the card: Bank card – which flips the card when clicked. The back side of the card reveals sensitive card data like its full number, expiration date, and CVV code. Although the card number is generally not considered private information, some applications still prefer not to show the full number by default, but only if the user initiates it. However, I know and even use banks that generally do not allow you to see the bank card number in the application. Show card details – by clicking this button, this feature supposedly generates a list of transactions on the card and displays them in the table below. It imitates the real functionality where users can generate reports on bank card transactions. In reality, these reports can be complex tables with many customizable filters and the ability to download the report as a file. Such operations might involve heavy computations, process a huge amount of data, making them resource-intensive and time-consuming. For the sake of the demo, it's simplified. Under the hood, the " " button triggers the previously discussed function, which simply blocks the main thread using the function, which was also discussed above. After that, static mock transaction data is simply rendered into the table. Generate report Generate report heavyWork() blockingTask() ایپلی کیشن کے رویے کو بائیں طرف کی ترتیب پینل پر مختلف ترتیبات کا استعمال کرتے ہوئے اپنی مرضی کے مطابق کیا جا سکتا ہے. اب یہ واضح کرنے کا وقت ہے کہ یہ کیا کرتا ہے: Main Thread blocking – یہ فیصلہ کرتا ہے کہ کیا Main Thread کو بلاک کیا جائے گا یا نہیں. Scheduler.yield() – چیک کرتا ہے کہ scheduler.yield() استعمال کیا جاتا ہے یا نہیں. Data array length – controls how many elements are iterated by the heavyWork() function. زیادہ عناصر، زیادہ وقت لگتا ہے. بلاکنگ وقت کی مدت - بیان کرتا ہے کہ میلیس سیکنڈ کے ہر عنصر کو پروسیسنگ کرنے کے لئے کتنا وقت لگتا ہے. ہائیڈ انٹرایکٹ – مقرر کرتا ہے کہ scheduler.yield() کتنی بار کہا جاتا ہے، اعداد و شمار کے ذریعے ترقی کے فیصد کے طور پر. یعنی، اس نمبر کو کم کرنے کے لئے، یہ زیادہ سے زیادہ بار کہا جائے گا. سابق مثالوں میں، ہم نے 10ms کی تاخیر اور 25٪ کے انٹرایکٹ کے ساتھ ایک 200 عنصر کے اعداد و شمار کا استعمال کیا ہے - زیادہ سے زیادہ تاخیر کے بغیر ظاہر اثر کے لئے ایک اچھا توازن. بڑے ڈیٹا سیٹ کے ساتھ، ایک چھوٹا سا انٹرایکٹ اکثر بہتر ہے. مظاہرہ کریں تمام سرگرمیوں اور ترتیبوں کو منتخب کرنے کے بعد، ہم ایک حقیقی استعمال سائنسی کے ذریعے چلے جائیں اور دیکھیں کہ کس طرح بنیادی ٹرانسمیشن کو بلاک کرنا صارف کے تجربے کو متاثر کرتی ہے. بلاک اور غیر فعال ہم بھی تھوڑا سا پیمانے کی لمبائی میں اضافہ کریں گے، لہذا بھاری آپریشن زیادہ وقت لگتا ہے، ہمیں اثرات کو دیکھنے کے لئے وقت دیتا ہے. " بٹن. اس منظر کے پیچھے، یہ اس فیشن، جس میں 1000 عناصر کو پروسیسنگ کرتا ہے، جہاں ہر عنصر 10 ملیس سیکنڈ لیتا ہے. Main Thread scheduler.yield() Generate report heavyWork() دیکھو کیا ہو رہا ہے: The " " بٹن بند رہتا ہے، یہ غیر پرنٹ نہیں ہوتا ہے، اور UI دوبارہ نہیں کرتا. جب رپورٹ پیدا ہو رہی ہے، صارف " پر کلک کرنے کی کوشش کرتا ہے. ’’پھر‘‘ " بٹنز، لیکن کچھ جواب نہیں دیتا. انٹرفیس مکمل طور پر منجمد ہے، کوئی انیمیشن نہیں ہے، کوئی تبصرہ نہیں ہے، کوئی ترقی کا احساس نہیں ہے. یہ ایک برا صارف کے تجربے کا ایک کلاسیک مثال ہے. ایپ منجمد لگتا ہے، اگرچہ تکنیکی طور پر یہ اب بھی کام کر رہا ہے. صارف کو معلوم نہیں ہے کہ کیا انتظار کرنا ہے یا صفحہ کو دوبارہ لوڈ کرنا ہے. Generate report Show card details Show balance ان نقصانات کو حل کرنے کے لئے استعمال کریں کچھ ترتیبات کو ترمیم کرتے ہوئے. یہاں ترتیب اب کی طرح نظر آتا ہے: اب بھی بند کر دیا گیا ہے. اس بار، استعمال کرنے کا اختیار اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ نہیں ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ اس کا مطلب یہ ہے کہ جواب کے انٹرفیس کو 5٪ تک کم کیا جاتا ہے کیونکہ میئر کی لمبائی میں اضافہ ہوا ہے. scheduler.yield() Main Thread scheduler.yield() scheduler.yield() اور اب اپ ڈیٹ کی ترتیب کے ساتھ، ایک ہی صارف فریم مکمل طور پر مختلف نظر آتا ہے. پہلی چیز جو آنکھیں پکڑتا ہے یہ ہے کہ " " بٹن پر کلک کیا گیا ہے، یہ درست طریقے سے ریڈنگ کرتا ہے، اور لوڈ انیمیشن ظاہر ہوتا ہے. رپورٹ پیدا ہونے کے دوران، صارف صارف صارف کے ساتھ کامیابی سے بات چیت کرتا ہے: وہ کارڈ کو پھینک سکتے ہیں اور توازن کو منتقل کر سکتے ہیں. ایپلی کیشن جواب دہ رہتا ہے، یہاں تک کہ اگر انیمیشن تھوڑا تھوڑا سا کم سست ہے، یہ پچھلے کے مقابلے میں ایک بڑا قدم آگے بڑھتا ہے. یہ ایک بہت بہتر تجربہ ہے. صارف کو مطلع کیا جاتا ہے، کنٹرول میں، اور یہ پتہ نہیں ہے کہ ایپلی کیشن کام کر رہا ہے. اور یہ سب کچھ لیا گیا تھا ... ایک طریقہ کار کال: یقینی طور پر، اصل تنصیب کو مزید بہتر بنایا جا سکتا ہے، لیکن یہاں تک کہ اس سادہ شکل میں، فرق حیرت انگیز ہے. Generate report scheduler.yield() نتیجہ لہذا، آج آپ کو آپ کے براؤزر کو ایک لمبائی دینے کے بارے میں سیکھا ہے، اس کے بارے میں بات کرنے کی اہمیت. اعلی تر ترجیحات کے کاموں کو انجام دینے کے لئے، اور ان تکنیکوں کے فوائد اور نقصانات. اس مضمون میں شامل نہیں کیا گیا ہے کہ دیگر صلاحیتیں ہیں. لیکن میرا مقصد آپ کو ایک مضبوط بنیاد دینے کے لئے تھا، تجربات شروع کرنے کے لئے کافی، اور آپ کے کوڈ کو براؤزر کے ساتھ کس طرح کھیلنے کے بارے میں مختلف طریقے سے سوچنے کے لئے شروع کرنے کے لئے کافی. پڑھنے کے لئے شکریہ، اور آپ کے براؤزر کو ایک بار پھر ایک لمحے دے! Main Thread Prioritized Task Scheduling API فائدہ مند بائیں آن لائن ڈیمو – https://let-your-browser-take-a-breather.onrender.com/ ڈیمو GitHub ریپیوٹر – https://github.com/WOLFRIEND/let_your_browser_take_a_breather ڈرائنگ – https://drive.google.com/file/d/1FLKKPaseyypE3pVXXn7Cj0aWac3rCayn/view