پنج روشی که AirSHIFT عملکرد زمان اجرا برنامه React خود را بهبود بخشید

مطالعه موردی در دنیای واقعی بهینه سازی عملکرد React SPA.

کنتو تسوجی
Kento Tsuji
ساتوشی آرای
Satoshi Arai
یوسوکه اوتسونومیا
Yusuke Utsunomiya
یوسوکه فوروکاوا
Yosuke Furukawa

عملکرد وب سایت فقط مربوط به زمان بارگذاری نیست. ارائه یک تجربه سریع و پاسخگو به کاربران، به ویژه برای برنامه های دسکتاپ با بهره وری که مردم روزانه از آنها استفاده می کنند، بسیار مهم است. تیم مهندسی در Recruit Technologies یک پروژه بازسازی را برای بهبود یکی از برنامه های وب خود، AirSHIFT ، برای عملکرد ورودی بهتر کاربر انجام دادند. در اینجا نحوه انجام آنها آمده است.

پاسخ آهسته، بهره وری کمتر

AirSHIFT یک برنامه وب دسکتاپ است که به صاحبان فروشگاه‌ها، مانند رستوران‌ها و کافه‌ها، کمک می‌کند تا کار شیفتی کارکنان خود را مدیریت کنند. این اپلیکیشن تک صفحه ای که با React ساخته شده است، ویژگی های مشتری غنی از جمله جداول شبکه ای مختلف از برنامه های شیفت سازماندهی شده بر اساس روز، هفته، ماه و موارد دیگر را ارائه می دهد.

تصویری از برنامه وب AirSHIFT.

از آنجایی که تیم مهندسی Recruit Technologies ویژگی‌های جدیدی را به برنامه AirSHIFT اضافه کرد، بازخورد بیشتری در مورد عملکرد کند مشاهده کردند. یوسوکه فوروکاوا، مدیر مهندسی AirSHIFT گفت:

در یک مطالعه تحقیقاتی کاربران، وقتی یکی از صاحبان فروشگاه گفت که پس از کلیک کردن روی دکمه، صندلی خود را ترک می کند تا قهوه دم کند، شوکه شدیم، فقط برای اینکه زمان انتظار برای بارگیری جدول شیفت را از بین ببرد.

پس از انجام تحقیقات، تیم مهندسی متوجه شد که بسیاری از کاربران آن‌ها سعی می‌کردند جداول شیفت بزرگ را روی رایانه‌های با مشخصات پایین بارگذاری کنند، مانند لپ‌تاپ Celeron M با فرکانس 1 گیگاهرتز مربوط به 10 سال پیش.

اسپینر بی پایان در دستگاه های ارزان قیمت.

برنامه AirSHIFT رشته اصلی را با اسکریپت‌های گران قیمت مسدود می‌کرد، اما تیم مهندسی متوجه نشدند که اسکریپت‌ها چقدر گران هستند زیرا در حال توسعه و آزمایش بر روی رایانه‌های با مشخصات غنی با اتصالات Wi-Fi سریع بودند.

نموداری که فعالیت زمان اجرا برنامه را نشان می دهد.
هنگام بارگذاری جدول شیفت، حدود 80 درصد از زمان بارگذاری توسط اسکریپت‌های اجرا شده مصرف می‌شود.

پس از نمایه سازی عملکرد آنها در Chrome DevTools با فعال بودن CPU و throttling شبکه، مشخص شد که بهینه سازی عملکرد مورد نیاز است. AirSHIFT یک کارگروه برای مقابله با این موضوع تشکیل داد. در اینجا 5 موردی که آنها روی آنها تمرکز کردند تا برنامه خود را به ورودی کاربر پاسخگوتر کنند، آورده شده است.

1. میزهای بزرگ را مجازی کنید

نمایش جدول شیفت به چندین مرحله گران نیاز داشت: ساخت DOM مجازی و نمایش آن بر روی صفحه متناسب با تعداد اعضای کارکنان و زمان‌بندی. به عنوان مثال، اگر یک رستوران 50 عضو شاغل داشته باشد و بخواهد برنامه شیفت ماهانه آنها را بررسی کند، جدول 50 (عضو) ضرب در 30 (روز) خواهد بود که منجر به ارائه 1500 جزء سلولی می شود. این یک عملیات بسیار گران است، به خصوص برای دستگاه های با مشخصات پایین. در واقع اوضاع بدتر بود. از تحقیقات آنها دریافتند مغازه‌هایی وجود دارد که 200 کارمند را مدیریت می‌کنند و به حدود 6000 جزء سلولی در یک جدول ماهانه نیاز دارند.

برای کاهش هزینه این عملیات، AirSHIFT جدول شیفت را مجازی کرد. این برنامه اکنون فقط اجزای داخل نما را نصب می کند و اجزای خارج از صفحه را جدا می کند.

یک اسکرین شات حاشیه‌نویسی که نشان می‌دهد AirSHIFT برای ارائه محتوا در خارج از نما استفاده می‌کرد.
قبل: رندر کردن تمام سلول های جدول shift.
یک اسکرین شات حاشیه‌نویسی که نشان می‌دهد AirSHIFT اکنون فقط محتوایی را ارائه می‌کند که در نمای دید قابل مشاهده است.
After: فقط رندر کردن سلول های داخل viewport.

در این مورد، AirSHIFT از react-virtualized استفاده کرد، زیرا الزاماتی در مورد فعال کردن جداول شبکه دو بعدی پیچیده وجود داشت. آنها همچنین در حال بررسی راه هایی برای تبدیل پیاده سازی به استفاده از پنجره واکنش سبک وزن در آینده هستند.

نتایج

مجازی سازی جدول به تنهایی زمان اسکریپت را 6 ثانیه کاهش می دهد (در 4 برابر کندی CPU + محیط Macbook Pro سریع 3G). این تاثیرگذارترین بهبود عملکرد در پروژه بازسازی بود.

اسکرین شات حاشیه‌نویسی از ضبط پانل عملکرد Chrome DevTools.
قبل: حدود 10 ثانیه اسکریپت پس از ورود کاربر.
اسکرین شات حاشیه‌نویسی دیگری از ضبط پانل عملکرد Chrome DevTools.
بعد از: 4 ثانیه از برنامه نویسی پس از ورودی کاربر.

2. حسابرسی با User Timing API

در مرحله بعد، تیم AirSHIFT اسکریپت هایی را که بر روی ورودی کاربر اجرا می شوند، بازسازی کردند. نمودار شعله Chrome DevTools امکان تجزیه و تحلیل آنچه را که واقعاً در موضوع اصلی اتفاق می‌افتد را ممکن می‌سازد. اما تیم AirSHIFT تجزیه و تحلیل فعالیت برنامه ها را بر اساس چرخه عمر React آسانتر یافت.

React 16 ردیابی عملکرد خود را از طریق User Timing API ارائه می‌کند که می‌توانید آن را از بخش Times در Chrome DevTools تجسم کنید. AirSHIFT از بخش Timeings برای یافتن منطق غیرضروری در حال اجرا در رویدادهای چرخه حیات React استفاده کرد.

بخش زمان بندی پانل عملکرد ابزارهای توسعه دهنده کروم.
رویدادهای زمان‌بندی کاربر React.

نتایج

تیم AirSHIFT متوجه شد که یک React Tree Reconciliation غیرضروری درست قبل از هر مسیریابی در حال انجام است. این بدان معنی بود که React قبل از ناوبری، جدول شیفت را به‌طور غیر ضروری به‌روزرسانی می‌کرد. به‌روزرسانی غیرضروری وضعیت Redux باعث این مشکل شده است. رفع آن حدود 750 میلی‌ثانیه در زمان اسکریپت صرفه‌جویی کرد. AirSHIFT بهینه‌سازی‌های کوچک دیگری را نیز انجام داد که در نهایت منجر به کاهش 1 ثانیه‌ای در زمان اسکریپت شد.

3. بارگذاری تنبلی اجزا و انتقال منطق گران قیمت به کارگران وب

AirSHIFT دارای یک برنامه چت داخلی است. بسیاری از صاحبان فروشگاه ها در حالی که به جدول شیفت نگاه می کنند از طریق چت با کارکنان خود ارتباط برقرار می کنند، به این معنی که کاربر ممکن است در حال تایپ پیامی در حین بارگیری جدول باشد. اگر رشته اصلی با اسکریپت هایی که جدول را رندر می کنند اشغال شده باشد، ورودی کاربر می تواند janky باشد.

برای بهبود این تجربه، AirSHIFT اکنون از React.lazy و Suspense استفاده می‌کند تا متغیرهایی را برای محتویات جدول نشان دهد و در عین حال اجزای واقعی را با تنبلی بارگیری کند.

تیم AirSHIFT همچنین برخی از منطق کسب و کار گران قیمت را در اجزای بارگذاری شده با تنبلی به کارگران وب منتقل کرد. این مسئله با آزاد کردن رشته اصلی به طوری که بتواند روی پاسخ دادن به ورودی کاربر تمرکز کند، مشکل جابجایی ورودی کاربر را حل کرد.

به طور معمول توسعه دهندگان در استفاده از کارگران با پیچیدگی روبرو هستند، اما این بار Comlink کارهای سنگین را برای آنها انجام داد. در زیر کد شبه نحوه کارکرد AirSHIFT یکی از گران‌ترین عملیات‌هایی که داشته‌اند آورده شده است: محاسبه کل هزینه‌های نیروی کار.

در App.js، از React.lazy و Suspense برای نمایش محتوای بازگشتی در حین بارگیری استفاده کنید

/** App.js */
import React, { lazy, Suspense } from 'react'

// Lazily loading the Cost component with React.lazy
const Hello = lazy(() => import('./Cost'))

const Loading = () => (
  <div>Some fallback content to show while loading</div>
)

// Showing the fallback content while loading the Cost component by Suspense
export default function App({ userInfo }) {
   return (
    <div>
      <Suspense fallback={<Loading />}>
        <Cost />
      </Suspense>
    </div>
  )
}

در جزء Cost، از comlink برای اجرای منطق calc استفاده کنید

/** Cost.js */
import React from 'react';
import { proxy } from 'comlink';

// import the workerlized calc function with comlink
const WorkerlizedCostCalc = proxy(new Worker('./WorkerlizedCostCalc.js'));
export default async function Cost({ userInfo }) {
  // execute the calculation in the worker
  const instance = await new WorkerlizedCostCalc();
  const cost = await instance.calc(userInfo);
  return <p>{cost}</p>;
}

منطق محاسباتی که در worker اجرا می شود را پیاده سازی کنید و آن را با comlink در معرض دید قرار دهید

// WorkerlizedCostCalc.js
import { expose } from 'comlink'
import { someExpensiveCalculation } from './CostCalc.js'

// Expose the new workerlized calc function with comlink
expose({
  calc(userInfo) {
    // run existing (expensive) function in the worker
    return someExpensiveCalculation(userInfo);
  }
}, self);

نتایج

علیرغم حجم محدود منطقی که به صورت آزمایشی کار کردند، AirSHIFT حدود 100 میلی‌ثانیه از جاوا اسکریپت خود را از رشته اصلی به رشته کارگر (شبیه‌سازی شده با 4x throttling CPU) منتقل کرد.

تصویری از ضبط پانل عملکرد Chrome DevTools که نشان می‌دهد اسکریپت‌نویسی در حال حاضر در وب‌کارگر به‌جای رشته اصلی انجام می‌شود.

AirSHIFT در حال حاضر در حال بررسی است که آیا می‌تواند اجزای دیگر را با تنبلی بارگذاری کند و منطق بیشتری را برای کارگران وب برای کاهش بیشتر jank بارگذاری کند.

4. تنظیم بودجه عملکرد

با اجرای همه این بهینه سازی ها، اطمینان از اینکه برنامه در طول زمان کارایی خود را حفظ می کند بسیار مهم بود. AirSHIFT اکنون از اندازه بسته استفاده می کند تا از اندازه فایل جاوا اسکریپت و CSS فعلی تجاوز نکند. جدای از تنظیم این بودجه های اولیه، آنها داشبوردی ساختند تا صدک های مختلف زمان بارگذاری جدول شیفت را نشان دهد تا بررسی کند که آیا برنامه حتی در شرایط غیر ایده آل هم کارایی دارد یا خیر.

  • زمان تکمیل اسکریپت برای هر رویداد Redux اکنون اندازه گیری می شود
  • داده های عملکرد در Elasticsearch جمع آوری می شود
  • اجرای صدک 10، 25، 50 و 75 هر رویداد با کیبانا تجسم شده است.

AirSHIFT اکنون رویداد بارگیری جدول شیفت را زیر نظر دارد تا مطمئن شود که در 3 ثانیه برای کاربران صدک 75 تکمیل می شود. این بودجه در حال حاضر اجرا نشده است، اما آنها در حال بررسی اعلان‌های خودکار از طریق Elasticsearch هستند که از بودجه آنها بیشتر شود.

نموداری که نشان می دهد صدک 75 در حدود 2500 میلی ثانیه، صدک 50 در حدود 1250 میلی ثانیه، صدک 25 در حدود 750 میلی ثانیه و صدک دهم در حدود 500 میلی ثانیه کامل می شود.
داشبورد Kibana داده‌های عملکرد روزانه را بر اساس صدک نشان می‌دهد.

نتایج

از نمودار بالا، می توانید متوجه شوید که AirSHIFT در حال حاضر بیشتر به بودجه 3 ثانیه ای برای کاربران صدک 75 می رسد و همچنین جدول شیفت را در عرض یک ثانیه برای کاربران صدک 25 بارگذاری می کند. با گرفتن داده های عملکرد RUM از شرایط و دستگاه های مختلف، AirSHIFT اکنون می تواند بررسی کند که آیا انتشار ویژگی جدید واقعاً بر عملکرد برنامه تأثیر می گذارد یا خیر.

5. هکاتون های اجرایی

حتی اگر همه این تلاش‌های بهینه‌سازی عملکرد مهم و تاثیرگذار بودند، همیشه آسان نیست که تیم‌های مهندسی و تجاری را در اولویت‌بندی توسعه غیرعملکردی قرار دهند. بخشی از چالش این است که برخی از این بهینه سازی های عملکرد را نمی توان برنامه ریزی کرد. آنها نیاز به آزمایش و تفکر آزمون و خطا دارند.

AirSHIFT اکنون در حال اجرای هکاتون‌های داخلی یک روزه است تا به مهندسان اجازه دهد فقط بر روی کارهای مربوط به عملکرد تمرکز کنند. در این هکاتون‌ها همه محدودیت‌ها را حذف می‌کنند و به خلاقیت مهندسان احترام می‌گذارند، به این معنی که هر پیاده‌سازی که به سرعت کمک می‌کند ارزش بررسی دارد. برای تسریع هکاتون، AirSHIFT گروه را به تیم‌های کوچک تقسیم می‌کند و هر تیم برای دیدن اینکه چه کسی می‌تواند بیشترین بهبود امتیاز عملکرد Lighthouse را کسب کند، رقابت می‌کند. تیم ها بسیار رقابتی می شوند! 🔥

عکس های هکاتون.

نتایج

رویکرد هکاتون به خوبی برای آنها کار می کند.

  • گلوگاه های عملکرد را می توان به راحتی با آزمایش چندین رویکرد در طول هکاتون و اندازه گیری هر کدام با Lighthouse شناسایی کرد.
  • پس از هکاتون، متقاعد کردن تیم که باید برای انتشار تولید در اولویت قرار گیرند، بسیار آسان است.
  • همچنین یک روش موثر برای حمایت از اهمیت سرعت است. هر شرکت کننده می تواند ارتباط بین نحوه کدنویسی و نحوه عملکرد آن را درک کند.

یک عارضه جانبی خوب این بود که بسیاری از تیم های مهندسی دیگر در Recruit به این رویکرد عملی علاقه مند شدند و تیم AirSHIFT اکنون چندین هکاتون سرعت را در شرکت تسهیل می کند.

خلاصه

کار کردن بر روی این بهینه‌سازی‌ها قطعا آسان‌ترین سفر برای AirSHIFT نبود، اما مطمئناً نتیجه داد. اکنون AirSHIFT جدول شیفت را در عرض 1.5 ثانیه در میانه بارگذاری می کند که 6 برابر بهتر از عملکرد آنها قبل از پروژه است.

پس از راه اندازی بهینه سازی عملکرد، یکی از کاربران گفت:

از اینکه بارگیری سریع جدول شیفت را انجام دادید بسیار متشکریم. تنظیم نوبت کاری در حال حاضر بسیار کارآمدتر است.