إدراج . يمكن أن تشعر التطبيقات على شبكة الإنترنت الحديثة بالغموض.في بعض الأحيان، كفاءة JavaScript طويلة الأمد كافية لتجفيف الاتصال، مما يترتب على المستخدمين الخوف والقلق من ما إذا كان التطبيق لا يزال يعمل أو تم تجفيزه. إدخال طريقة صغيرة ولكن قوية: يسمح للمستخدم بتوقف التشغيل ، مما يمنح المتصفح فرصة للتعامل مع المهام الأكثر أهمية (مثل التخطيط أو الكتابة) ، ثم الاستمرار في المكان الذي وقعت فيه. ، استكشاف العملات القديمة ، واقرأ كيف جعل الحياة أسهل. التخطيط المهني API الوسائط .yield() Main Thread scheduler.yield() ما هو التحديث.yield( ) لذلك، ما هو وهذه هي طريقة من انترنت من جديد تتيح لك هذه الطريقة، كمتطوع، إلغاء إجراء JavaScript الخاص بك وتقديم التحكم بشكل واضح إلى الموقع. - حتى يمكنها التعامل مع المهام الأخرى المهمة المتوقعة، مثل التفاعلات المستخدمة، والتسريبات، وما إلى ذلك، ثم الاستمرار في تنفيذها من حيث لم تكن متوقعة. أنت تقول لـ Browser: scheduler.yield() التوقيت التخطيط المهني API. Main Thread scheduler.yield() "انتظري، استرخي نفسك، دعنا نوقف العمل الحالي ونتركز على المهام الأخرى غير الأقل أو الأكثر أهمية. "انتظري، استرخي نفسك، دعنا نوقف العمل الحالي ونتركز على المهام الأخرى غير الأقل أو الأكثر أهمية. هذا يجعل صفحتك أكثر استجابة، وخاصة عند تشغيل وظائف جاكوارت طويلة أو شديدة. - ما هو كل شيء عن السرعة التي يستجيب المتصفح إلى الدخول المستخدم. التفاعل مع Next Paint (INP) الترجمة قبل التفكير في التفكير، دعونا نذهب بسرعة إلى بعض النصائح الأساسية التي ستستخدم طوال المقال. العنصر الرئيسي هو المكان الرئيسي حيث يقوم المتصفح بتنفيذ معظم عمله، ويقوم بتصوير وتصميم وتشغيل معظم رمز JavaScript الخاص بك. مهمة طويلة – هذه هي أي مهمة في جاكوارت تعمل على الحفاظ على الشبكة الرئيسية مشغولة لفترة طويلة، عادة ما أكثر من 50 ميلي ثانية. مهمة الحظر هي عملية متكاملة على الشبكة الرئيسية التي تمنع المتصفح من معالجة أشياء مهمة أخرى، مثل الإجابة على النقرات أو تحديث UI. المشكلة . لتفهم الجمال في يجب عليك أولاً أن تفهم المشكلة التي يحاولون حلها. يوتيوب يعمل على نطاق واحد. وهذا يعني أنه يمكن أن يفعل شيء واحد فقط في وقت واحد. إذا كان الكود الخاص بك يحافظ على نطاق النطاق مشغولاً، كل شيء آخر - الترجمة والضغط على الأقراص، والرسائل الدخولية يجب أن تنتظر. في عالم مثالي، سوف تقضي دائمًا تقسيم المهام الشديدة إلى أجزاء صغيرة. ولكن الواقع هو غامض. أنت تتعامل مع الكود الأصلي، ورسائل من جهة ثانية، أو الحسابات الشديدة التي لا يمكن تجنبها. وإذا حدث ذلك، فإن المستخدمين يغادرون صفحتين مغلقة. scheduler.yield() نموذج التطبيق JavaScript. كمعالجة سريعة ، إليك نموذج من كيفية معالجة JavaScript المهام - بمعنى آخر ، كيفية أنا متأكد من أن الكثير منك قد رأيت الشبكات مثل هذا قبل – الشبكات المرتبطة بالمهام، والخلفية الحوادث، والخلفية الدعوة. JavaScript Execution Model دعونا نلقي نظرة على الأفكار الرئيسية خطوة بخطوة: كل الكود يذهب مباشرة إلى Call Stack وتنتهي خطوة بعد خطوة، وظيفة بعد وظيفة. إنه يتبع مبادئ LIFO - آخر في، أول من. يتم معالجة العمليات غير المباشرة (مثل setTimeout، fetch) خارج الشبكة الرئيسية - من خلال API Web (مقدمة من قبل المتصفح أو البيئة). بعد أن تم إجراءها ، لا تذهب مباشرة إلى Stack Call. بدلاً من ذلك ، يتم إجراء مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مكالمة مك عندما يكون كوب الدعوة فارغًا ، يتم التحقق من سلسلة المهمات الصغيرة وتشغيل جميع المهمات الصغيرة واحدة في الترتيب. فقط بعد ذلك ، يحصل على وظيفة ماكروية واحدة من الجانب وتشغيلها. إذا تم إضافة ميكروفونات جديدة خلال العملية، يتم تشغيلها قبل ميكروفونات التالية، وبالتالي يتم تحديد ميكروفونات جديدة دائمًا. هذا الدورة لا تزال تنتهي: كل ميكروستراتيجيات → ميكروستراتيجيات واحدة → تكرار. New synchronous code gets into the when new tasks arrive, like a user clicking a button, a new script being run, or when a or runs its callback. Call Stack microtask macrotask هذه عبارة مختصرة ومفصلة للغاية ، فقط لتذكرك كيف تعمل ، لأنها ستتواصل بعمق مع الموضوع. وصف المشكلة. الآن، عندما كنت قد بدأت تفهم كيفية تنفيذ وظائف JavaScript، دعونا نلقي نظرة على المشكلة الحقيقية التي تأتي مع هذا النموذج. المشكلة بسيطة: عندما يستغرق وظيفتك وقتًا طويلاً على النحاس الرئيسي، فإنه يمنع كل شيء آخر - التفاعلات المستخدمة، وإعادة تدوير التحديثات، والتحليلات. هذا يؤدي إلى تجميد UI ورفع الاستجابة السلبية. ولكن دعونا نكون حريصين على التفكير الأول: "نعم، لا نكتب الميزات الطويلة أو الشديدة، وبالتالي لا نكون أولئك الذين يسببونها في الأصل". وحتى لو لم تكن أنت "الطبيعة" لهذا السلوك، فهذا صحيح - في عالم مثالي، يجب من أجل ذلك ، سنقوم بإنشاء وظيفة تسمى وهذا يعمل كمهام مكثفة لملف الرئيسي لفترة زمنية محددة، وهذا الميزات يثبت هذا النوع من الحسابات "الشديدة" على كل عنصر من المجموعة. 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. أريد أن أذكر أن 200 العناصر ليست كثيرة، ولكن هذا سيكون كافياً لمعرفة جوهر المشكلة. بعد ذلك، يتم إنشاء مجموعة جديدة "النتائج" الخلفية لتخزين القيم المعالجة. الخط 5 يُعَدُّ مُعَدًّا يُعَدُّ مُعَدًّا يُعَدُّ مُعَدًّا يُعَدُّ مُعَدًّا يُعَدُّ مُعَدًّا. داخل اللوحة ، نقوم بتشغيل وظيفة BlockingTask() ، وتثبيت 10 ميلي ثانية من العمل لكل عنصر ، ويتم إضافة النتيجة إلى مجموعة "النتائج". مرة أخرى ، أريد أن أذكرك أن ، بالنسبة للتعليقات ، فإن وظيفة BlockingTask() لا تحتوي على أي تكلفة سمعية. في النهاية ، فإنه يعود إلى المجموع الناجح. فقط 10 ميلي ثانية لكل عنصر ، و فقط 200 عنصر - ولكن معا ، فإنها تغلق العنصر الرئيسي لمدة 2 ثانية كاملة. المشكلة في التعبير الآن حان الوقت للتفكير في المشكلة ليس فقط في النظرية، ولكن في العمل.هذه ليست نموذجًا كاملاً حتى الآن - فكر في ذلك كشخصية بسيطة لمساعدتك على رؤية المشكلة بشكل واضح. إليكم ما تراه: يتيح لك نافذة اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين اليمين يتم تشغيل نافذة تسمى "مهمة ضخمة" التي تعمل على وظيفة heavyWork() ، وهي تلك التي تعمل على معالجة مجموعة باستخدام blockingTask() على كل عنصر إذا تم تشغيل الحد من الصلب الرئيسي. وتتضمن نافذة تسمى "Logger" فقط الوقت الحالي إلى الكازينو، بما في ذلك ميلي ثانية. دعونا نرى ماذا سيحدث عندما يتم إلغاء التخطيط ، لذلك تكون المهام سهلة للغاية. إنها مجرد زاوية على مجموعة من 200 العناصر ، دون أي حسابات معقدة. Main Thread ما تراه: يستخدم المستخدم على الزر "OK" - يتم تشغيل وظيفة heavyWork() ، ثم يعود على الفور. وهذا يعرض على الرسالة HEAVY_TASK_DONE في الكازينو ، ثم ينتقل إلى النتيجة - مجموعة من الأرقام. ثم يضغط المستخدم على زر "تسجيل الدخول" ثلاث مرات ، لتسجيل الوقت الحالي إلى القفل - تظهر علامات الزمن على الفور ، مع اختلاف صغير في الوقت. يقوم المستخدم بتشغيل وظيفة heavyWork() مرة أخرى، ومرة أخرى، الاستجابة الفورية. في النهاية ، يغلق المستخدم اثنين من النوافذ ، والتي في الواقع فقط إزالة هذه العناصر من DOM. في هذه الحالة ، كل شيء يشعر بسرعة ومزيد من الاستجابة. لا يوجد مشكلات مع المتصفح مع التعامل مع التفاعلات ، لأن الشريان الرئيسي يظل مفتوحا. الآن، دعونا نتمكن من التخزين، بحيث يكون لكل عنصر من العنصر، سوف يتم إدخال الميزات مع تأخير فقط 10 ميلي ثانية. Main Thread blockingTask() ويمكنك الآن أن ترى أن التفاعل المستخدم مع عناصر UI أصبح أصغر بكثير، وقد ظهرت خلطات UI. دعونا نضعها على ما يحدث هنا وما يمكنك مشاهدته من ذلك: يتحرك المستخدم على زر "OK" ، وبالتالي يتم تشغيل وظيفة heavyWork() .وأول التوقف الذي يحدث هو أن زر "OK" يظل ضعيفًا.لماذا؟ لأنه لا يستطيع المتصفح إعادة التصوير في حين أن heavyWork() لا يزال يمنع العنق الرئيسي.وذلك من المهم أن ندرك أننا لا نتحدث فقط عن المهمة الحالية ولكن عن الكمبيوتر المحمول ككل. خلال هذا الوقت، يستعرض المستخدم أربعة مرات على زر "تسجيل الدخول" - لا يحدث شيء. يتم تسجيل الدخول ورفع مستخدميها إلى الجانب، ولكن المستعرض لا يستطيع التفاعل. فقط بعد انتهاء heavyWork()، يمكنك أن ترى النتائج في الكازينو: أولاً نتيجة heavyWork()، ثم أربعة علامات الزمن - كلها تم إخراجها في مجموعة واحدة. بعد ذلك، يضغط المستخدم على الزر "OK" مرة أخرى. نفس السلوك - ضغط الزر. ثم، في حين أن مهمة heavyWork() يتم تشغيلها، يحاول إغلاق نافذة من خلال ضغط الزر "X" ثلاث مرات. مرة أخرى، لا إجابة بصرية. فقط عندما ينتهي العمل لا نرى النوافذ تنتهي. وأخيرا، محاولة أخرى لبدء heavyWork() وتغلق النوافذ الأخيرة. ماذا يظهر هذا الإعلان؟ يظهر هذا الإعلان البسيط مدى مدة الأنشطة التي تمنع إمكانية المتصفح للرد على الإجراءات المستخدمة. على الرغم من أن كل مكالمة التخطيط تستغرق 10 ميلي ثانية فقط، فإن سلسلة 200 منهم معاً يؤدي إلى إغلاق لمدة 2 ثانية. لا يمكن للمستخدم التفاعل مع القفازات، ولا يتم إعادة التصوير. لا يتم إجراء الحوادث في صفوف، ولكن لا يتم معالجةها حتى يتم إزالتها. هذا ليس فقط مشكلة الأداء، بل هو مشكلة تجربة المستخدم. وهذه هي نفس النوع من المشكلة التي نريد حلها - على الأرجح، دون الحاجة إلى تقسيم منطقنا تدريجياً إلى عشرات من الردود. حل المشكلة . الآن عندما تفهم المشكلة ، دعنا نتحدث عن الحلول المحتملة. بالطبع ، فإن أفضل استراتيجية هو تجنب المهام الطويلة في البداية من خلال الحفاظ على الكود الفعلي والتفكير في الأمور في وقت مبكر. ولكن ، كما رأينا ، هناك أشياء تحدث. سواء كان هذا هو الكود الأخير ، الحسابات لا يمكن تجنبها ، أو ليس لديك وقت كاف للتحسين ، في بعض الأحيان ، عليك أن تتعامل معه. وظهرت العديد من التغييرات والتجهيزات لتعزيز الاستجابة، ولكن الفكرة الأساسية خلف جميعها - وراءها أيضا - هو بسيط للغاية: Prioritized Task Scheduling API scheduler.yield() تقسيم المهمة إلى أجزاء صغيرة أو ما يسمى بقطع. و مرة واحدة من وقت لآخر ، تأخذه لترك المتصفح يقطع رءوسها. بمعنى آخر، يمكنك أن تمنح الرماد الرئيسي فرصة لإجراء المهام أكثر احتياجاً، مثل التفاعل مع المستخدمين أو إصدار التحديثات، ثم تأتي إلى الانتهاء من عملك. هكذا هو مفهوم كما هو الحال في 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: يتم إنشاء وعد وتشغيلها على الفور، وتخطط لإنشاءTimeout() مع تأخير صفر. يتم إنشاء إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال إرسال الخطوة 9: نحن نقدر كم مرة نريد أن نعود إلى الشريط الرئيسي، حوالي كل 25% من العمل. الخطوط 13-15: داخل اللوحة، إذا تمكنت من تلبية المعيار، يتم نقل التشغيل إلى العنق الرئيسي، أي يتم تكرار تقنية 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 } الآن وظيفتك الخاصة - النقطة التالية من الوظيفة - قد تتأخر من خلال واحدة أو أكثر من هذه الإرشادات المتكررة. يقوم المتصفح فقط بتشغيل أي شيء في الشارع، ولا يمكنك التحكم في النظام. نوع من السماح لك بإعطاء، لا تعرف بالضبط متى ستحصل على السيطرة مرة أخرى. heavyWork() setTimeout() هناك طرق أخرى للتعامل مع هذه الحالة، ويمكن أن يكون الميزات التي تسمح لك بتخطيط العمل مباشرة قبل التعديل التالي. أو لديه مشاكل مماثلة، أو هذا يعمل على تشغيل رمزك خلال وقت مفقود من المتصفح. فهو ليس بديلًا تمامًا، ولكن جيدًا للخلفية، والعمل الأقل أهمية، مما يساعد على الشريان الرئيسي أن يكون مجانيًا للأنشطة الأكثر أهمية. بشكل عام، يمكننا التحدث عن استراتيجيات أخرى لتحديد وتجنب مثل هذه المشكلات. ومع ذلك، للحفاظ على الموضوع، دعونا ننتقل إلى المستقبل ونرى ما ارفعها إلى طاولة requestAnimationFrame() setTimeout() requestIdleCallback() scheduler.yield() اقرأ المزيد ( - هو وسيلة حديثة للتوقف عن التنفيذ، وتحقيق السيطرة على العنصر الرئيسي، مما يسمح للمستعرض بتنفيذ أي عمل متوقعا ذات الأولوية العالية، ثم الاستمرار في التنفيذ من حيث وقعت. يتم الوصول إلى التعبير، يتم إلغاء تنفيذ الوظيفة الحالية التي تم دعوتها، وتقديم السيطرة على العنق الرئيسي، وبالتالي إزالة، أو إلغاء، المهمة الحالية. 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() الأولوية لذلك، ما هو السبب في مثل هذه الفرق في السلوك؟ كل شيء عن الأولوية! كالمطورين، نحن لا نعتقد عادة عن الترتيب في تنفيذ المهام في حلقات الأحداث من حيث الأولوية. و ولكن إذا كنت تبحث أكثر عمقًا، فسوف تلاحظ أن هناك أيضًا ترجيحات مفرطة في اللعب. على سبيل المثال، سوف يقوم ممارس اللعب على القفص، الذي يتم إطلاقه بواسطة إجراء المستخدم، عادةً قبل إجراء كلاهما، على الرغم من أن كلاهما كما ذكرت سابقاً، وهي جزء من – واجهة واسعة ومتنوعة من الميزات التي تستحق محاضرة كاملة منفصلة وتتجاوز بشكل واضح نطاق هذه المحاضرة، ومع ذلك، من المهم أن نذكر واحدة من خصائصها الرئيسية: إنشاء نموذج أهمية مهمة واضحة. microtasks macrotasks setTimeout() macrotasks scheduler.yield() Prioritized Task Scheduling API "المحافظة على المستخدمين" - المهام ذات الأولوية العالية التي تؤثر بشكل مباشر على التفاعل المستخدم، مثل معالجة النقرات والمقاطع، والعمليات المهمة لـ UI. "المظهر المستخدمي" - المهام التي تؤثر على رؤية UI أو المحتوى، ولكنها ليست هامة للتوصل الفوري. "الخلفية" - المهام التي ليست عاجزة، ويمكن إلغاءها بأمان دون التأثير على تجربة المستخدم الحالي، ولا تكون مرئية للمستخدم. وبالتالي، لديه “ «الأولى» أيضاً، إظهار هذه طريقة، والتي تهدف إلى إعداد المهام مع أولويات محددة من أعلى. على الرغم من أنه لن يذهب إلى التفاصيل عن هذه الطريقة هنا، فمن المهم أن نذكر أن إذا تم تصميمها من داخل لكنها تتألف من أهميتها. 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() يمكن تخصيص سلوك التطبيق باستخدام الإعدادات المختلفة في منصة التحكم على الجانب الأيسر. قد ترى إصدارًا بسيطًا من التطبيق في الصور السابقة. الآن حان الوقت لتفسير ما يفعله: إزالة الشريط الرئيسي - يحدد ما إذا كان الشريط الرئيسي سيتم إزالته، في الواقع، عندما يتم تشغيل هذا الخيار، يتم تنفيذ وظيفة BlockingTask(). Scheduler.yield() - يحدد ما إذا كان scheduler.yield() مستخدمًا. طول المجموعات البيانات - يسيطر على عدد العناصر التي يتم تكرارها من خلال وظيفة heavyWork().أكثر العناصر، أطول فترة ممكنة. مدة الحظر - يحدد كم من ميلي ثانية كل عنصر من المجموعة يستغرق معالجة. يحدد مدى تكرار scheduler.yield() ، بوصفها نموذجًا من التقدم من خلال المجموع. وهذا يعني أن هذا الرقم أقل بكثير من ذلك. في الأمثلة السابقة ، استخدمنا مجموعة 200 عنصرًا مع التوقيت 10ms ومدى 25٪ - توازنًا جيدًا للتأثير المرئي دون التوقيت المفرط. مع مجموعة أكبر من البيانات ، غالبا ما يكون التوقيت الصغير أفضل. ولكن كما هو الحال دائما ، يعتمد ذلك. التظاهرات بعد تقسيم جميع الوظائف والتصميم ، دعونا نذهب من خلال سياق الاستخدام الحقيقي ونرى كيف يؤثر تحويل القناة الرئيسية على تجربة المستخدم. إلغاء وإلغاء سوف نزيد أيضًا طوله المجموعة قليلاً ، لذلك يستغرق العملية الضخمة وقتًا أطول ، مما يمنحنا وقتًا للانتباه إلى الآثار. " على خلفية السيناريوهات ، هذا يجعل الفعالية التي تعمل على 1000 عنصر ، حيث يستغرق كل عنصر 10 ميلي ثانية. Main Thread scheduler.yield() Generate report heavyWork() شاهد ما يحدث: The " " يظل القفز ، لا يغلق ، ولا يعود UI. أثناء إنتاج التقرير ، يحاول المستخدم الرد على " « ثم » " القفازات، ولكن لا يردد.المصالحة مجهولة تمامًا، ليس هناك الترفيه، لا تعليقات، لا شعور بالتقدم.هذه هي مثالًا كلاسيكيًا لمجرد تجربة المستخدم الخبيثة.تظهر التطبيق مجهولة، على الرغم من أنها تكنولوجيًا لا تزال تعمل.المستخدم لا يعرف ما إذا كان من المقرر الانتظار أو تحميل الصفحة. Generate report Show card details Show balance دعونا نلقي نظرة على هذه الخلافات باستخدام من خلال تعديل بعض التكوينات. هكذا تبدو التكوين الآن: لا تزال مستمرة، هذه المرة، فإن خيار استخدام يتم تشغيلها. يزداد طول المجموع بسهولة، فقط من أجل الشفافية. لا يزال الوقت المحدد هو نفس، 10 ميلي ثانية. يتم تقليل مدة الاستجابة إلى 5 في المائة للحصول على استجابة أكثر صرامة، حيث تم زيادة مدة المجموع. scheduler.yield() Main Thread scheduler.yield() scheduler.yield() والآن مع الإعدادات المتجددة ، تبدو نفس حركة المستخدم مختلفة تمامًا. تم إعادة تشغيلها بشكل صحيح، وتظهر إثارة الحمل. أثناء إنتاج التقرير، يستخدم المستخدم بنجاح التفاعل مع UI: يمكنهم التبديل بطاقة وبدء التوازن. يبقى التطبيق موثوقاً، حتى لو كانت الإثارة أقل صعوبة قليلاً، وهذا خطوة هائلة نحو المضي قدماً مقارنة بالخلفية السابقة. هذا هو تجربة أفضل بكثير. يتم إعلام المستخدم، في التحكم، ولا تترك تخيل ما إذا كان التطبيق يعمل. وكل ما كان عليه هو... اتصال طريقة واحدة: وبطبيعة الحال ، يمكن تحسين التطبيق الفعلي ، ولكن حتى في هذا الشكل البسيط ، فإن الفرق هو مدهش. Generate report scheduler.yield() النتيجة لذلك، اليوم تعلمت عن إعطاء المتصفح الخاص بك استراحة، أهمية التقدم إلى للقيام بمهمات أولوية أعلى، والفوائد والضعف من هذه التقنيات. لديها القدرات الأخرى التي لم تكن محصورة في هذه المقالة. ولكن هدفي كان من أجل إعطاءك أساسًا قويًا، كافية للبدء في التجربة، وكافية للبدء في التفكير بشكل مختلف حول كيفية تلعب الكود الخاص بك مع المتصفح. شكرا لك على القراءة، وإعطاء متصفحك استراحة مرة واحدة في وقت واحد! Main Thread Prioritized Task Scheduling API اليمين المفيدة العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور على العثور. Demo GitHub repository – https://github.com/WOLFRIEND/let_your_browser_take_a_breather كاميرا – https://drive.google.com/file/d/1FLKKPaseyypE3pVXXn7Cj0aWac3rCayn/view