نلفت انتباهكم اليوم إلى ترجمة المادة الثانية من سلسلة مخصصة لتحسين instagram.com. سنركز هنا على تحسين آلية التنفيذ المبكر لاستعلامات GraphQL وعلى زيادة كفاءة نقل بيانات HTML إلى العميل.

→ قراءة مع التنفس بملل ،
الجزء الأولإرسال البيانات بواسطة الخادم إلى العميل باستخدام تقنية تنزيل HTML التدريجي
في الجزء الأول ، تحدثنا عن كيفية استخدام آليات التحميل المسبق ، لبدء تنفيذ الاستعلامات في المراحل الأولى من معالجة الصفحة. هذا - حتى قبل تحميل البرنامج النصي الذي يبدأ مثل هذه الطلبات. بالنظر إلى ذلك ، يمكن الإشارة إلى أن تنفيذ هذه الطلبات في مرحلة تحميل المواد لا يزال يعني أن تنفيذها لم يبدأ قبل تقديم صفحة HTML على العميل. وهذا بدوره يعني أنه لا يمكن بدء الطلب قبل أن يرسل العميل طلب الخادم ورد الخادم على هذا الطلب (هنا تحتاج أيضًا إلى إضافة الوقت الذي يستغرقه الخادم لإنشاء استجابة HTML للعميل). في الشكل التالي ، يمكنك أن ترى أن بداية استعلام GraphQL يمكن أن تتأخر تمامًا. وهذا - بالنظر إلى أننا نبدأ في تنفيذ هذه الطلبات باستخدام الكود الموجود في علامة HTML
<head>
، وأن هذه واحدة من المهام الأولى التي نحلها بمساعدة أدوات تحميل البيانات مسبقًا.
التنفيذ الأولي للطلب يبدأ بتأخير ملحوظمن الناحية النظرية ، ستبدو بداية استعلام GraphQL مثاليًا في اللحظة التي يتم فيها إرسال طلب تحميل الصفحة المقابلة إلى الخادم. ولكن كيف تجعل المتصفح يبدأ تنزيل شيء ما حتى قبل أن يتلقى بعض أكواد HTML على الأقل من الخادم؟ الجواب هو إرسال المورد إلى المتصفح بمبادرة من الخادم. قد يبدو أنه لتطبيق مثل هذه الآلية ، ستحتاج إلى شيء مثل HTTP / 2 Server Push. ولكن ، في الواقع ، هناك تقنية قديمة جدًا (غالبًا ما يتم نسيانها) تتيح لك تنفيذ مخطط مماثل للتفاعل بين العميل والخادم. تتميز هذه التقنية بدعم المستعرض العالمي ، حيث لا توجد حاجة إلى الخوض في تعقيدات البنية الأساسية التي تعتبر نموذجية لتطبيق HTTP / 2 Server Push. يستخدم Facebook هذه التقنية منذ عام 2010 (اقرأ عن
BigPipe ) ، وفي مواقع أخرى مثل Ebay ، يجد التطبيق أيضًا في أشكال مختلفة. ولكن يبدو أن مطوري جافا سكريبت لتطبيقات الصفحة الواحدة إما يتجاهلون هذه التكنولوجيا أو لا يستخدمونها. إنها تدور حول تحميل HTML تدريجيًا. تُعرف هذه التقنية بأسماء مختلفة: "التدفق المبكر" و "مسح الرأس" و "HTML التدريجي". إنه يعمل بفضل مزيج من آليتين:
- الأول هو ترميز نقل HTTP المقسم.
- والثاني هو التقديم التدريجي لـ HTML في المتصفح.
ظهرت آلية
تشفير النقل المقسم في HTTP / 1.1. يسمح لك بتقسيم استجابات HTTP إلى العديد من الأجزاء الصغيرة التي يتم إرسالها إلى المستعرض في وضع التدفق. يقوم المتصفح "بتثبيت" هذه الأجزاء فور وصولها ، مكونًا رمز الاستجابة الكامل منها. على الرغم من أن هذا النهج يوفر تغييرات كبيرة في الطريقة التي يتم بها تكوين الصفحات على الخادم ، فإن معظم اللغات والأطر لديها القدرة على تقديم إجابات مماثلة ، مقسمة إلى أجزاء. تستخدم الواجهة الأمامية لـ Instagram على الويب Django ، لذلك نستخدم كائن
StreamingHttpResponse . السبب الذي يجعل استخدام مثل هذه الآلية مفيدًا هو أنه يسمح لك بإرسال محتوى HTML للصفحة إلى المستعرض في وضع التدفق حيث تكون الأجزاء الفردية من الصفحة جاهزة ، بدلاً من الانتظار حتى يكون كود الصفحة بالكامل جاهزًا. هذا يعني أنه يمكننا مسح عنوان صفحة المتصفح فورًا تقريبًا بعد تلقي الطلب (ومن هنا يأتي مصطلح "التدفق المبكر"). لا يتطلب إعداد الرأس موارد خادم كبيرة بشكل خاص. يتيح هذا للمتصفح بدء تحميل البرامج النصية والأنماط حتى عندما يكون الخادم مشغولا في إنشاء بيانات ديناميكية لبقية الصفحة. دعونا نلقي نظرة على تأثير هذا الأسلوب. هذا هو ما يشبه تحميل الصفحة العادي.
لا يتم استخدام تقنية التدفق المبكر: لا يبدأ تحميل الموارد حتى يتم تحميل صفحة HTML بالكاملولكن ماذا يحدث إذا قام الخادم ، عند استلام الطلب ، بتمرير عنوان الصفحة على الفور إلى المتصفح.
يتم استخدام تقنية التدفق المبكر: تبدأ الموارد في التحميل فور إلقاء علامات HTML على المستعرضبالإضافة إلى ذلك ، يمكننا استخدام آلية إرسال رسائل HTTP في أجزاء لإرسال البيانات إلى العميل لأنها جاهزة. في حالة التطبيقات التي يتم تقديمها على الخادم ، يمكن تقديم هذه البيانات في شكل كود HTML. ولكن إذا كنا نتحدث عن التطبيقات ذات الصفحة الواحدة مثل instagram.com ، فيمكن للخادم أيضًا نقل شيء مثل بيانات JSON إلى العميل. من أجل إلقاء نظرة على كيفية عمل ذلك ، دعنا نلقي نظرة على أبسط مثال على بدء تطبيق صفحة واحدة.
أولاً ، يتم إرسال علامة HTML الأصلية إلى المستعرض الذي يحتوي على رمز JavaScript المطلوب لعرض الصفحة. بعد تحليل هذا البرنامج النصي وتنفيذه ، سيتم تنفيذ طلب XHR ، وتحميل البيانات المصدر اللازمة لعرض الصفحة.
عملية تحميل صفحة في موقف حيث يطلب المستعرض بشكل مستقل من الخادم كل ما يحتاج إليهتتضمن هذه العملية العديد من المواقف التي يرسل فيها العميل طلبًا إلى الخادم وينتظر استجابة منه. نتيجة لذلك ، هناك فترات يكون فيها كل من الخادم والعميل غير نشطين. بدلاً من انتظار الخادم لانتظار طلب API من العميل ، سيكون أكثر فعالية إذا بدأ الخادم العمل على إعداد استجابة API فور إنشاء كود HTML. بعد أن كان الجواب جاهزًا ، يمكن للخادم ، بمبادرة منه ، تسميمه على العميل. هذا يعني أنه بحلول الوقت الذي يكون فيه العميل قد أعد كل ما هو مطلوب لتصور البيانات التي تم تحميلها مسبقًا بعد اكتمال طلب واجهة برمجة التطبيقات ، فمن المحتمل أن تكون هذه البيانات جاهزة. لن يضطر العميل إلى تلبية طلب منفصل إلى الخادم وانتظر استجابة منه.
تتمثل الخطوة الأولى في تطبيق نظام التفاعل بين العميل والخادم هذا في إنشاء ذاكرة تخزين مؤقت JSON مصممة لتخزين استجابات الخادم. قمنا بتطوير هذا الجزء من النظام باستخدام كتلة نصية صغيرة مدمجة في كود HTML للصفحة. إنه يلعب دور ذاكرة التخزين المؤقت ويحتوي على معلومات حول الطلبات التي سيتم إضافتها إلى ذاكرة التخزين المؤقت بواسطة الخادم (هذا ، في شكل مبسط ، يظهر أدناه).
<script type="text/javascript">
بعد إعادة تعيين رمز HTML إلى المستعرض ، يمكن للخادم تنفيذ طلبات API بشكل مستقل. بعد تلقي الإجابات على هذه الطلبات ، سيقوم الخادم بنقل بيانات JSON إلى الصفحة في شكل علامة نصية تحتوي على هذه البيانات. عندما يتلقى المستعرض جزءًا مشابهًا من كود HTML للصفحة ويقوم بتحليله ، سيؤدي ذلك إلى حقيقة أن البيانات ستسقط في ذاكرة التخزين المؤقت JSON. الشيء الأكثر أهمية هنا هو أن المستعرض سيعرض الصفحة تدريجياً - حيث يتلقى شظايا من الاستجابة (أي أنه سيتم تنفيذ الكتل النصية المكتملة عند وصولها إلى المستعرض). هذا يعني أنه من الممكن تمامًا إنشاء كميات كبيرة من البيانات على الخادم وإفلات كتل البرامج النصية على الصفحة بمجرد أن تكون البيانات المقابلة جاهزة. سيتم تنفيذ هذه البرامج النصية على الفور على العميل. هذا هو أساس نظام BigPipe الذي يستخدمه Facebook. هناك ، يتم تحميل العديد من أجهزة الاستدعاء المستقلة بالتوازي على الخادم ويتم إرسالها إلى العميل عند توفرها.
<script type="text/javascript"> window.__dataLoaded('/my/api/path', {
عندما يكون البرنامج النصي للعميل جاهزًا لطلب البيانات التي يحتاجها ، فإنه بدلاً من تنفيذ طلب XHR ، يتحقق أولاً من ذاكرة التخزين المؤقت JSON. إذا كانت ذاكرة التخزين المؤقت تحتوي بالفعل على نتائج الاستعلام ، فسيتلقى البرنامج النصي على الفور ما يحتاج إليه. إذا كان الطلب قيد التقدم ، سينتظر البرنامج النصي النتائج.
function queryAPI(path) { const cacheEntry = window.__data[path]; if (!cacheEntry) {
كل هذا يؤدي إلى حقيقة أن عملية تحميل الصفحة تصبح هي نفسها كما في الرسم البياني التالي.
عملية تحميل صفحة في موقف يشارك فيه المستعرض بنشاط في إعداد البيانات للعميلإذا قارنت ذلك مع أسهل طريقة لتحميل الصفحات ، فقد اتضح أن الخادم والعميل يمكنهم الآن القيام بمزيد من المهام في نفس الوقت. هذا يقلل من وقت التوقف عن العمل الذي ينتظر فيه الخادم والعميل بعضهما البعض.
كان لهذا التحسين تأثير إيجابي للغاية على نظامنا. لذلك ، في متصفحات سطح المكتب ، بدأ تحميل الصفحة يكمل 14٪ أسرع من ذي قبل. وفي متصفحات الجوال (نظرًا للتأخير الطويل في شبكات المحمول) ، بدأت الصفحة في التحميل بمعدل 23٪ بشكل أسرع.
أعزائي القراء! هل تخطط لاستخدام المنهجية لتحسين تشكيل صفحات الويب التي تمت مناقشتها هنا في مشاريعك؟
