حدود الأداء للتفاعل الأصلي وكيفية التغلب عليها

لا تروض التنين ، اركبه

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

الرد الأصلي تحت غطاء محرك السيارة

من أجل فهم قيود الأداء في React Native ، يجب أولاً أن نلقي نظرة على أعمالها الداخلية. من أجل الوضوح ، سأحاول الحفاظ على هذا الجزء رفيع المستوى. إذا كنت تبحث عن التفاصيل الرائعة ، فراجع هذا المنشور الممتاز لـ Tadeu Zagallo.

أحد الأماكن الرئيسية في React Native هو تقديم تجربة التطبيق الأصلية التي توقعها مستخدمو الأجهزة المحمولة - مع التركيز على كفاءة المطور استنادًا إلى Javascript و React. بمعنى آخر ، على الرغم من أن معظم كود تطبيقنا مكتوب بلغة Javascript ، فإن واجهة المستخدم الخاصة بالتطبيق نفسه أصلي تمامًا.

هذا يعني أن تطبيقنا يعمل عبر عالمين مختلفين:

  • المجال الأصلي - مملكة Objective-C / Swift في iOS و Java في Android. هذا هو المكان الذي نتعامل فيه مع نظام التشغيل وحيث يتم تقديم جميع المشاهدات. يتم التعامل مع واجهة المستخدم حصريًا في الخيط الرئيسي ، ولكن يمكن أن يكون هناك آخرون لحساب الخلفية. React Native يفعل معظم الرفع الثقيل في هذا المجال بالنسبة لنا.
  • JS realm - يتم تنفيذ Javascript في خيطها المنفصل بواسطة محرك Javascript. عادة ما يتم تطبيق منطق أعمالنا ، بما في ذلك طرق العرض المراد عرضها وكيفية تصميمها ، هنا.

لا يمكن الوصول إلى المتغيرات المعرفة في مجال واحد مباشرة في الآخر. هذا يعني أن كل الاتصالات بين العالمين يجب أن تتم بشكل واضح عبر الجسر. هذا في الواقع مماثل في المفهوم لكيفية اتصال العملاء والخوادم عبر الويب - يجب إجراء تسلسل للبيانات من أجل المرور. حكاية رائعة - عندما تقوم بتصحيح رمز RN JS الخاص بك في Chrome ، يتم تشغيل المجالين فعليًا على أجهزة كمبيوتر مختلفة (سطح المكتب والجهاز المحمول) ويمر الجسر بينهما عبر WebSocket.

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

React ، بمفهومها الظاهري DOM ، يوفر لنا تحسين ممتاز خارج الصندوق. يتم إجراء تغييرات غير متزامنة على المكونات التي تم تقديمها في JS مع خوارزمية فرق ذكية - وبالتالي تقليل مقدار البيانات المرسلة عبر الجسر. هذا هو في الواقع السبب وراء كون React Native أكثر أداءً من التقنيات المنافسة مثل Appcelerator التي سبقتها لعدة سنوات.

اللعب مع حالة استخدام الحياة الحقيقية

رؤية البطاقة القابلة للضبط على اليسار؟ إنه نمط UX شائع للجوال يستخدم في تطبيقات مثل Google Now.

من المثير للدهشة أيضًا تطبيق الأداء الحكيم.

سننفذ هذا المثال عدة مرات ونرى آثار الأداء لكل نهج.

من المنطقي إنشاء مكون قابل لإعادة الاستخدام Swipeable يضيف سلوك التمرير (ترجمة x وتغيير التعتيم) إلى أي مكون محتوى نعطيه كطفل - في هذه الحالة.

تنفيذنا الأول - PanResponder

لنبدأ بالنهج المباشر. بما أننا نرغب في الاستماع على إيماءات اللمس ، فسنستخدم React Native's PanResponder. في كل مرة نتلقى فيها حدث نقل ، سنقوم بحساب العتامة الجديدة والترجمة x استنادًا إلى إجمالي المسافة الأفقية المقطوعة ، وتحديثها باستخدام الحالة المحلية:

ما الأداء الذي يجب أن نتوقعه من هذا النهج؟ دعونا نتذكر الإرشادات المذكورة سابقًا - من أجل تصميم تطبيقات React Native للأداء المعماري ، يجب أن نمرر الجسر إلى أدنى حد ممكن.

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

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

ألم أقرأ شيئا في مستندات حول التلاعب المباشر؟

إذا كنت تهتم بالأداء ، فربما تكون قد قرأت مستندات التغطية ، وتذكرت هذه المقالة بشكل غامض حول التلاعب المباشر بالمكونات.

تبدو واعدة ، لنقم بتحديث المكون الأصلي مباشرة وتحسين الأداء! سنقوم بتجربته ، إليك التنفيذ:

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

تقليديًا ، من أجل تحديث مكون React ، يتعين علينا إعادة تقديمه. إذا كان التحديث الخاص بنا مترجماً للغاية ، مثل تغيير نمط معين (الترجمة x والتعتيم) ، يمكننا أن نجعله جراحياً مباشرةً دون التقديم التام والمصالحة. يتعارض هذا مع "حالة ذهنية" React ، لذلك من الأفضل عدم القيام بذلك في كثير من الأحيان وقصر أنفسنا على حالات الاستخدام حيث لدينا خاصية معينة تتغير بسرعة كبيرة (على سبيل المثال ، أثناء الرسوم المتحركة).

هل يمكننا العودة إلى حل مشكلة الجسر؟

أحد أجمل الأشياء في React Native هو أنه يمكننا أن نأخذ أي جزء من قاعدة بياناتنا وننقله بسهولة إلى أصلي - حتى مجرد مكون واحد.

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

نظرًا لأن أحداث اللمس تنشأ في المجال الأصلي ، فما الذي سيحدث إذا قمنا بتحديثات x للترجمة والتعتيم في اللغة الأم أيضًا؟ إلق نظرة:

الجزء الوحيد الذي انتقلنا إليه إلى موطنه الأصلي هو مكون حاوية Swipeable. هذا من شأنه أن يضمن أنفسنا 60 FPS ويبدو أن الرمز هو في الواقع أقصر. لاحظ أن مكونات محتوى البطاقة الخاصة بنا ظلت في وضع JS خالص. إليك كيفية استخدام صفنا الأصلي داخل تخطيط JS الخاص بنا:

مستقبل رد الفعل الأصلي

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

من الممكن تصميم واجهات ذكية JS من شأنها أن تقلل من المرور فوق الجسر وتصل إلى نفس النتائج. ماذا لو في مثالنا ، لم يكن رمز JS الخاص بنا بحاجة إلى تحديث المجال الأصلي في كل إطار؟ ماذا لو استطعنا تحديد مرة واحدة فقط ، في بداية التفاعل ، ما هي الخصائص التي يتم تأمينها لأي حدث أصلي ، والسماح لبعض الوحدات الأصلية في الجزء الداخلي الداخلي من React Native بإلغاء تحميل التحديثات بالنسبة لنا؟ هذا سيجعلنا نعبر الجسر مرة واحدة فقط - في البداية.

يتفاعل React Native في هذا الاتجاه ، وأحد المعالجات الأساسية التي تلقيناها هي مكتبة الرسوم المتحركة الجديدة. لننفذ مثالنا للمرة الرابعة والأخيرة مع تطبيق Animated in JS النقي:

كما ترون ، تعامل مكتبة Animated الرسوم المتحركة والتفاعلات بطريقة تصريحية للغاية. إذا استطعنا أن نعلن كيف يتفاعل التفاعل ، يمكن إجراء تسلسل لهذا الإعلان وإرساله عبر الجسر. يفتح ذلك إمكانية قيام وحدة نمطية أصلية عامة بمعالجة التفاعل بالنسبة لنا وإلغاء تحميل الإطار بواسطة تحديثات الإطار.

لسوء الحظ ، فإن تطبيق Animated الحالي (يونيو 2016) لا يفرغ كل شيء إلى موطنه الأصلي هذا يعني أن تنفيذنا الرابع لا يزال يعاني في الوقت نفسه من عنق الزجاجة نفسه. بعد قولي هذا ، يتم إحراز تقدم وأنا واثق من أن الإصدارات المستقبلية ستتيح لنا التغلب على قيود الجسور من JS في العديد من الحالات.

مقارنة جميع التطبيقات الأربعة

القراءة عن الأداء لا تتشابه مع الشعور بالواقع. يمكنك اللعب مع إصدارات تعمل بالكامل من التطبيقات الأربعة في الريبو التالي ، مقدم جنبًا إلى جنب لسهولة المقارنة:

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

خاتمة و فراق الكلمات

يعد تطوير تطبيقات الأجهزة المحمولة في React Native أمرًا رائعًا ، ولكن الراحة في بعض الأحيان تأتي بسعر. من الممكن تخفيف كل مشكلات الأداء تقريبًا ، والمفتاح هو فهم ما يجري تحت الغطاء.

في Wix.com ، نحن مهووسون بـ UX وتقديم تجربة المستخدم الأصلية التي توقعها مستخدمو الهاتف المحمول. فيما يلي إرشاداتنا التقريبية حول الأداء التفاعلي الهوس:

  1. ابدأ بتنفيذ كل شيء في JS لتحقيق أقصى قدر من الإنتاجية. لا تبالغ في التحسين مبكرًا.
  2. في المناطق المعرضة للإفراط في استخدام الجسور ، مثل الرسوم المتحركة / التفاعلات - تفضل المكتبات التوضيحية مثل الرسوم المتحركة. يمكن التعبير عن العديد من التفاعلات بشكل مُعلن وعلى الرغم من أنها قد لا تكون بديهية في البداية (انظر تطبيقنا الرابع) ، إلا أنها تستحق كل هذا الجهد.
  3. انتظر المنتج الكامل على جهاز حقيقي لمعرفة أين يتعثر التطبيق الخاص بك.
  4. إذا فشلت تحسينات React التقليدية ، فقم بنقل الأجزاء المزعجة جراحياً إلى مواطنها. نحافظ على نسبة حوالي 10 ٪ من المطورين الأصليين في فرقنا الهندسية لهذا الغرض.
  5. شجع مطوري JS على المشاركة في اللغة الأم. إنها أداة قوية لاستخدامها في المكان الصحيح وليست بعيدة المنال. لا يمكن التعبير عن بعض التفاعلات المعقدة بإفراغ وتفريغها من قبل المكتبات مثل الرسوم المتحركة.