لغة JavaScript مقسَّمة للرمز

يؤثر تحميل موارد JavaScript كبيرة بشكل كبير في سرعة الصفحة. تقسيم الشاشة جافا سكريبت لديك إلى أجزاء أصغر وتنزيل ما هو ضروري فقط يمكن أن يؤدي تشغيل صفحة ما أثناء بدء التشغيل إلى زيادة تحميل الصفحة سرعة الاستجابة، ما قد يؤدي بدوره إلى تحسين التفاعل مع المحتوى التالي في صفحتك مدى استجابة الصفحة لتفاعلات المستخدم (INP)

عندما تقوم الصفحة بتنزيل ملفات JavaScript كبيرة وتحليلها وتجميعها، يمكن أن تصبح غير مستجيب لفترات زمنية. عناصر الصفحة مرئية، حيث أنها من لغة HTML الأولية للصفحة ويتم تصميمها بواسطة CSS. ومع ذلك، نظرًا لأن لغة JavaScript المطلوبة لتشغيل هذه العناصر التفاعلية - بالإضافة إلى النصوص البرمجية الأخرى التي تم تحميلها بواسطة الصفحة — ربما تقوم بتحليل JavaScript وتنفيذها لكي تعمل. تشير رسالة الأشكال البيانية هي أن المستخدم قد يشعر كما لو أن التفاعل كان كبيرًا أو متأخرًا أو حتى مكسورًا تمامًا.

يحدث هذا غالبًا بسبب حظر سلسلة التعليمات الرئيسية بسبب تحليل JavaScript وتجميعها في سلسلة التعليمات الرئيسية. وإذا استغرقت هذه العملية وقتًا طويلاً، قد لا تستجيب عناصر الصفحة بسرعة كافية لإدخال المستخدم. علاج واحد لهذا هو تحميل JavaScript الذي تحتاجه فقط لكي تعمل الصفحة، بينما تأجيل محتوى JavaScript آخر لتحميله لاحقًا من خلال أسلوب يُعرف باسم التقسيم. تركز هذه الوحدة على الطريقة الثانية من هاتين الأسلوبين.

تقليل تحليل JavaScript وتنفيذها أثناء بدء التشغيل من خلال تقسيم الرموز البرمجية

يعرض Lighthouse تحذيرًا عندما يستغرق تنفيذ JavaScript وقتًا أطول من مرتَين ويفشل عندما يستغرق أكثر من 3.5 ثانية. JavaScript زائد يشكّل التحليل والتنفيذ مشكلة محتملة في أي نقطة من الصفحة لأنّ ذلك قد يؤدي إلى زيادة تأخير الإدخال في التفاعل إذا كان الوقت الذي يتفاعل فيه المستخدم مع الصفحة يتزامن مع اللحظة فإن مهام سلسلة التعليمات الرئيسية المسؤولة عن معالجة وتنفيذ JavaScript هي الجري.

والأكثر من ذلك، أن الإفراط في تنفيذ وتحليل JavaScript إشكالية في أثناء التحميل الأولي للصفحة، حيث إن هذه هي النقطة في الصفحة من المحتمل جدًا أن يتفاعل المستخدمون مع الصفحة. في الواقع، مقياس إجمالي وقت الحظر (TBT) مرتبط بشكل كبير. باستخدام مقياس INP، ما يشير إلى أنّ المستخدمين يميلون بشكل كبير إلى إجراء تفاعلات أثناء التحميل الأولي للصفحة.

عملية تدقيق Lighthouse التي توضح الوقت المُستغرق في تنفيذ كل ملف JavaScript أن طلبات الصفحات مفيدة، إذ يمكنها مساعدتك في تحديد قد تكون النصوص البرمجية مرشحة لتقسيم الرمز. يمكنك بعد ذلك الذهاب إلى أبعد من ذلك من خلال باستخدام أداة التغطية في "أدوات مطوري البرامج في Chrome" لتحديد أجزاء لا يتم استخدام JavaScript في الصفحة أثناء تحميل الصفحة.

تقسيم الرمز هو أسلوب مفيد يمكن أن يقلّل من محتوى JavaScript الأولي لإحدى الصفحات. والحمولات. تسمح لك بتقسيم حزمة JavaScript إلى جزأين:

  • JavaScript المطلوبة عند تحميل الصفحة، وبالتالي لا يمكن تحميلها على أي صفحة الوقت.
  • الجزء المتبقي من JavaScript الذي يمكن تحميله في وقت لاحق، غالبًا في النقطة التي يتفاعل فيها المستخدم مع عنصر تفاعلي معين في الصفحة.

يمكن تقسيم الرمز باستخدام البنية ديناميكية import(). هذا النمط البنية، على عكس عناصر <script> التي تطلب مورد JavaScript محدّدًا أثناء بدء التشغيل — يقوم بطلب للحصول على مورد JavaScript في وقت لاحق أثناء لدورة حياة الصفحة.

document.querySelectorAll('#myForm input').addEventListener('blur', async () => {
  // Get the form validation named export from the module through destructuring:
  const { validateForm } = await import('/validate-form.mjs');

  // Validate the form:
  validateForm();
}, { once: true });

في مقتطف JavaScript السابق، يتم تغيير وحدة validate-form.mjs عدم تنزيلها وتحليلها وتنفيذها إلا عندما يبلغ المستخدم أيًا من نماذج <input> حقل في هذه الحالة، فإن مورد JavaScript المسؤول عن فإن تشغيل منطق التحقق من صحة النموذج لا يتم تضمينه في أي وقت إلا في الصفحة عندما للاستخدام الفعلي على الأرجح.

يمكن استخدام حزم JavaScript، مثل webpack وParcel وRollup وesbuild لتقسيم حزم JavaScript إلى أجزاء أصغر كلما مواجهة استدعاء import() ديناميكي في رمز المصدر. تقوم معظم هذه الأدوات هذا تلقائيًا، ولكن يتطلب الإنشاء على وجه التحديد أن توافق على ذلك التحسين.

ملاحظات مفيدة حول تقسيم الرموز

على الرغم من أنّ تقسيم الرموز يعدّ طريقة فعالة للحدّ من التعارض بين سلاسل الرموز الرئيسية. أثناء التحميل الأولي للصفحة، من المفيد مراعاة بعض الأشياء إذا قررت لمراجعة رمز مصدر JavaScript بحثًا عن أي فرص لتقسيم الرمز.

استخدام أداة التجميع إن أمكن

من الشائع أن يستخدم المطوّرون وحدات JavaScript أثناء تطوير البرامج. إنه تحسين ممتاز لتجربة المطوّر يحسن قابلية قراءة التعليمات البرمجية وقابلية صيانتها. ومع ذلك، هناك بعض خصائص الأداء دون المستوى الذي يمكن أن تنتج عند شحن JavaScript إلى الإنتاج.

والأهم من ذلك، يجب استخدام أداة تجميع لمعالجة المصدر وتحسينه. بما في ذلك الوحدات التي تنوي تقسيم الرمز إليها. تكون الحزم فعالة جدًا في لن يقتصر الأمر على تطبيق التحسينات على رمز المصدر JavaScript، بل سيتم أيضًا فعّالة جدًا في موازنة اعتبارات الأداء مثل حجم الحزمة مقابل نسبة الضغط. تزداد فعالية الضغط مع حجم الحزمة، بينما تحاول برامج التجميع أيضًا ضمان ألا تكون الحزم كبيرة جدًا لدرجة أنها المهام الطويلة بسبب تقييم النص.

تتجنّب الحِزم أيضًا مشكلة شحن عدد كبير من الوحدات غير المجمّعة. عبر الشبكة. غالبًا ما يكون لدى البنى التي تستخدم وحدات JavaScript وأشجار الوحدات المعقدة. عندما يتم فصل أشجار الوحدات، فإن كل وحدة تمثل طلب HTTP منفصل، وقد يتأخر التفاعل في تطبيق الويب إذا لا تجمع الوحدات. في حين أنه من الممكن استخدام <link rel="modulepreload"> تلميح للموارد لتحميل وحدات الأشجار الكبيرة في وقت مبكر قدر الإمكان، تظل حِزم JavaScript أفضل من أداء التحميل وجهة النظر.

لا توقِف عن غير قصد فيديو مجمّع البث

يوفر محرك JavaScript V8 من Chromium عددًا من التحسينات بطريقة مبتكرة لضمان تحميل رمز JavaScript للإنتاج بأكبر قدر ممكن من الكفاءة. يُعرف أحد هذه التحسينات باسم تجميع البث، مثل التحليل التدريجي للغة HTML التي يتم بثها إلى المتصفح — يجمّع أجزاءً متدفقة من JavaScript عند وصولها من الشبكة.

ثمة طريقتان لضمان إنشاء بث مباشر مجمّع تطبيق الويب في Chromium:

  • ننصحك بتحويل رمز الإنتاج لتجنُّب استخدام وحدات JavaScript. الحِزم يمكنك تحويل رمز مصدر JavaScript استنادًا إلى هدف التجميع الهدف غالبًا ما يكون محددًا لبيئة معينة. سيسري V8 البث التحويل البرمجي إلى أي رمز JavaScript لا يستخدم وحدات، ويمكنك إعداد أداة التجميع لتحويل رمز وحدة JavaScript إلى بنية لا يستخدم وحدات JavaScript وميزاتها.
  • إذا أردت شحن وحدات JavaScript إلى قناة الإصدار العلني، استخدِم .mjs الإضافة. سواء كانت لغة JavaScript للإنتاج تستخدم وحدات، فهناك لا نوع محتوى خاص لـ JavaScript الذي يستخدم وحدات مقابل JavaScript إلا أنها لا تستخدم. بالنسبة إلى V8، يمكنك إيقاف البث بفعالية التحويل البرمجي عند شحن وحدات JavaScript في مرحلة الإنتاج باستخدام .js الإضافة. إذا كنت تستخدم الإضافة .mjs لوحدات JavaScript، بإمكان V8 أن يتم بث التحويل البرمجي لشفرة JavaScript المستندة إلى الوحدات مكسور.

لا تدع هذه الاعتبارات تثنيك عن استخدام تقسيم الرموز. رمز برمجي التقسيم طريقة فعالة لخفض حمولات JavaScript الأولية للمستخدمين، ولكن من خلال استخدام أداة التجميع ومعرفة كيف يمكنك الحفاظ على إمكانية بث V8 يمكنك التأكد من أنّ رمز JavaScript للإنتاج للمستخدمين كما ينبغي.

الإصدار التجريبي للاستيراد الديناميكي

حزمة ويب

يتم تضمين webpack مع مكوّن إضافي باسم SplitChunksPlugin، ما يتيح لك تهيئة كيفية تقسيم أداة التجميع لملفات JavaScript. تتعرف عليها حزمة webpack على حد سواء عبارات import() ديناميكية وimport ثابتة. سلوك يمكن تعديل SplitChunksPlugin من خلال تحديد الخيار chunks في التكوين:

  • chunks: async هي القيمة التلقائية، وتشير إلى طلبات import() الديناميكية.
  • تشير السمة chunks: initial إلى مكالمات import الثابتة.
  • تشمل chunks: all عمليات الاستيراد import() الديناميكية وعمليات الاستيراد الثابتة، ما يتيح لك لمشاركة المجموعات بين عمليات الاستيراد من async وinitial.

بشكل تلقائي، عندما تواجه حزمة webpack عبارة import() ديناميكية. هو/هي تنشئ مقطعًا منفصلاً لتلك الوحدة:

/* main.js */

// An application-specific chunk required during the initial page load:
import myFunction from './my-function.js';

myFunction('Hello world!');

// If a specific condition is met, a separate chunk is downloaded on demand,
// rather than being bundled with the initial chunk:
if (condition) {
  // Assumes top-level await is available. More info:
  // https://v8.dev/features/top-level-await
  await import('/form-validation.js');
}

ينتج عن إعداد حزمة الويب التلقائية لمقتطف الرمز السابق اثنان أجزاء منفصلة:

  • يمكن للمقطع main.js الذي تصنفه webpack على أنه مقطع initial، والذي تتضمّن الوحدة main.js و./my-function.js.
  • مقطع async، الذي يتضمن form-validation.js فقط (الذي يحتوي على تجزئة الملف في اسم المورد في حال إعداده). تم تنزيل هذا المقطع فقط. إذا كانت قيمة condition ثابتة

تتيح لك هذه الإعدادات تأجيل تحميل مجموعة "form-validation.js" حتى مطلوبة بالفعل. يمكن أن يؤدي ذلك إلى تحسين استجابة التحميل من خلال تقليل النص البرمجي التقييم أثناء التحميل الأولي للصفحة. تنزيل النص البرمجي وتقييمه للمقطع form-validation.js عندما يتم استيفاء شرط محدد، في وفي هذه الحالة، يتم تنزيل الوحدة النمطية التي يتم استيرادها ديناميكيًا. قد يكون أحد الأمثلة شرط يتم فيه تنزيل رمز polyfill لمتصفّح معيّن فقط، أو - كما في المثال السابق - الوحدة التي تم استيرادها ضرورية لتفاعل المستخدم.

من ناحية أخرى، يؤدي تغيير إعدادات SplitChunksPlugin لتحديد تضمن chunks: initial تقسيم الرمز على الأجزاء الأولية فقط. وهي مثل تلك المستوردة بشكل ثابت، أو المدرجة في entry من حزمة الويب . بالنظر إلى المثال السابق، سيكون المقطع الناتج form-validation.js و main.js في ملف نص برمجي واحد، ما قد يؤدي إلى تدهور أداء التحميل الأولي للصفحة.

يمكن أيضًا ضبط خيارات SplitChunksPlugin لفصل القيم الأكبر. نصوص برمجية إلى عدة نصوص أصغر، مثلاً باستخدام الخيار maxSize توجيه حزمة الويب لتقسيم المجموعات إلى ملفات منفصلة إذا تجاوزت المحددة بواسطة maxSize. يمكن أن يؤدي تقسيم ملفات النصوص البرمجية الكبيرة إلى ملفات أصغر تحسين استجابة التحميل، كما هو الحال في بعض الحالات مع تقييم النصوص البرمجية الذي يكلف وحدة المعالجة المركزية (CPU) وتقسيم العمل إلى مهام أصغر، والتي من غير المرجح أن تمنع لفترات زمنية أطول.

بالإضافة إلى ذلك، يعني إنشاء ملفات JavaScript أكبر أن النصوص البرمجية من المرجح أن يعانون من إبطال ذاكرة التخزين المؤقت. على سبيل المثال، إذا كنت تشحن ونص برمجي كبير مع كلٍّ من رمز إطار العمل ورمز تطبيق الطرف الأول، يمكن إلغاء صلاحية الحِزمة إذا تم تحديث إطار العمل فقط، ولكن لا شيء آخر في المورد المجمّع.

من ناحية أخرى، تزيد ملفات النصوص البرمجية الأصغر من احتمالية ظهور يسترد الزائر الموارد من ذاكرة التخزين المؤقت، مما يؤدي إلى تحميل الصفحة بشكل أسرع على الزيارات المتكررة. ومع ذلك، تستفيد الملفات الأصغر حجمًا من الضغط بشكل أقل من الملفات الأكبر حجمًا من المحتمل أن تؤدي إلى زيادة مدة الذهاب والعودة للشبكة في عمليات تحميل الصفحات باستخدام ذاكرة التخزين المؤقت للمتصفح. يجب توخي الحذر لتحقيق التوازن بين التخزين المؤقت والكفاءة وفعالية الضغط ووقت تقييم النص البرمجي.

الإصدار التجريبي من webpack

العرض التوضيحي لحزمة الويب SplitChunksPlugin.

اختبِر معلوماتك

نوع عبارة import المستخدم عند تنفيذ الرمز البرمجي تقسيم؟

import() ديناميكي
إجابة صحيحة.
قيمة import ثابتة
يُرجى إعادة المحاولة.

أيّ نوع من عبارة import يجب أن يكون في الأعلى من وحدة جافا سكريبت وليس في مكان آخر؟

import() ديناميكي
يُرجى إعادة المحاولة.
قيمة import ثابتة
إجابة صحيحة.

عند استخدام SplitChunksPlugin في حزمة الويب، ما هي الفرق بين مقطع async مقطع initial؟

تم تحميل async مجموعة باستخدام السمة import() الديناميكية. وinitial مجموعة باستخدام import
إجابة صحيحة.
يتم تحميل async مجموعة باستخدام القيمة import الثابتة. وinitial مجموعة باستخدام الخصائص الديناميكية import()
يُرجى إعادة المحاولة.

التالي: صور التحميل الكسول وعناصر <iframe>

وعلى الرغم من أنها تميل إلى أن تكون نوعًا مكلفًا إلى حد ما من الموارد، فإن لغة JavaScript ليست فقط نوع المورد الذي يمكنك تأجيل تحميله. صورة وعناصر <iframe> موارد باهظة الثمن في حد ذاتها. على غرار JavaScript، يمكنك يمكنها تأجيل تحميل الصور وعنصر <iframe> من خلال التحميل الكسول ، كما هو موضح في الوحدة التالية من هذه الدورة التدريبية.