نکات مهم جهت بهبود کارایی و سرعت لود صفحات در ASP.NET AJAX
  در این مقاله به بررسی برخی تکنیک های مهم جهت بالا بردن راندمان و کارایی صفحات وب و بارگذاری سریعتر وب سایت های ASP.NET AJAX می پردازم
   Ajax
   ۲۷۳۵۹
   این مقاله حاوی فایل ضمیمه نمی باشد
   مرتضی صحراگرد
   ۱۳۸۷/۸/۴
ارسال لینک صفحه برای دوستان ارسال لینک صفحه برای دوستان  اضافه کردن به علاقه مندیها اضافه کردن به علاقه مندیها   نسخه قابل چاپ نسخه قابل چاپ

 

مقدمه :

یکی از مواردی که در چند ماه اخیر توسط بازدید کنندگان سایت 30sharp به طور مکرر عنوان شده است، سنگین شدن صفحات و پایین آمدن سرعت لود و کارایی صفحات، هنگام استفاده از ASP.NET AJAX می باشد.
قبل از اینکه این مقاله را آغاز کنم، لازم می دانم که به یاد آوری چند مطلب بپردازم. همیشه وقتی قرار باشد که یک تکنولوژی پیچیده، مورد استفاده همگان قرار گیرد، باید یک سری پارامتر ها را فدای ایجاد سهولت و سادگی نمود.
اصولا برنامه نویسی  AJAX با هر کتابخانه ای (.... & Anthem  &  ASP.NET AJAX & Ajax Pro) اگر قرار باشد به بهترین نحو خود انجام شود، کار ساده ای نیست و نیازمند در نظر گرفتن مسایل بسیار زیادی از جمله امنیت، کارایی، سرعت، سازگار بودن با مرورگرهای مشهور، زیبایی وغیره می باشد. که باید با توجه به شرایط موجود، استراتژی مشخصی را اتخاذ کرد.
این موضوع نیازمند آن است که برنامه نویس تسلط نسبی بر کتابخانه ای که در حال استفاده از آن است داشته باشد. پس نمی توان راه حل واحدی را جهت رفع تمام مشکلات ارایه داد.
ولی در این بین، راه حل هایی کلی نیز وجود دارند که رعایت آنها باعث می شود که کارایی صفحات به طور چشمگیری افزایش یابد و سرعت لود صفحات چندین برابر گردد. در این مقاله به معرفی این نکات می پردازم.

آغاز :

ScriptManager و UpdatePanel دو تا از کنترل های بسیار مهم ASP.NET AJAX می باشند.

ScriptManager :

 ScriptManager در حقیقت مغز متفکر کتابخانه ASP.NET AJAX می باشد. در صفحاتی که قرار است از ASP.NET AJAX استفاده شود، حتما باید یک کنترل  ScriptManager در صفحه وجود داشته باشد. این کنترل با توجه به امکاناتی که از ASP.NET AJAX در صفحه استفاده شده است، اسکریپت های مورد نیاز برای انجام درست کارها از اسمبلی System.Web.Extensions.dll استخراج نموده و به صفحه اضافه می نماید.
کنترل ScriptManager دارای دو صفت مهم می باشد که در کارایی صفحات وب نقش بسیار مهمی دارند.

  • ScriptMode
  • LoadScriptsBeforeUI

هسته اصلی کتاب خانه ASP.NET AJAX یک فایل جاوا اسکریپت می باشد به نام MicrosoftAjax.js که در اسمبلی System.Web.Extensions.dll تعبیه شده است.
این فایل دارای دو نسخه می باشد به نام های MicrosoftAjax.js وMicrosoftAJAX.debug.js.
نسخه MicrosoftAJAX.debug.js بسیار سنگین تر از MicrosoftAjax.js می باشد و دارای مقدار کدهای زیادی جهت اعتبارسنجی و کامنت ها و غیره می باشد و مخصوص استفاده در زمان برنامه نویسی می باشد و امکاناتی جهت دیباگ نمودن و رفع مشکلات برنامه نویسی را دارا می باشد.
مثلا در نسخه MicrosoftAJAX.debug.js داخل متدهای این کتابخانه قطعه کدهایی نوشته شده است که نوع (Type) پارامترهایی را که به متد ارسال شده است را بررسی می کند و در صورتی که نوع مناسبی نباشد، خطای مشخصی را ایجاد می نماید و برنامه نویس متوجه اشتباه خود می گردد. ولی پس این که برنامه نوشته و به اندازه کافی آزمایش شد و نوبت به فاز Deployment رسید، دیگر نیاز نیست از این فایل استفاده شود.
نسخه MicrosoftAjax.js شامل قطعه کدهای مورد نیاز جهت دیباگ برنامه نیست و در نتیجه بسیار سبک تر می باشد. هنگامی که قرار است وب سایت به طور رسمی مورد استفاده قرار گیرد باید از این نسخه استفاده شود.
وظیفه خصوصیت ScriptMode در کنترل ScriptManager دقیقا همین است و با استفاده از این خصوصیت می توانیم مشخص کنیم که از کدام نسخه استفاده شود.
مقدار پیشفرض این خصوصیت Auto می باشد. وقتی مقدار آن Auto باشد، کنترل ScriptManager با توجه به نوع Deployment تصمیم می گیرد که از کدام نسخه استفاده نماید.
اگر وب سایت به صورت Release مورد Deploy واقع شده باشد، کترل ScriptManager از نسخه MicrosoftAjax.js استفاده می کند و اگر به صورت Debug مورد Deploy واقع شده باشد از نسخه MicrosoftAJAX.debug.js.
خصوصیت ScriptMode می تواند دو مقدار دیگر را نیز بپذیرد که با استفاده از آنها می توانیم به طور صریح به ScriptManager اعلام کنیم که از کدام نسخه استفاده نماید. اگر مقدار Release را به این خصوصیت نسبت دهیم، صرف نظر از هر چیزی، کنترل ScriptManager از نسخه MicrosoftAjax.js استفاده می نماید و اگر مقدار Debug را به آن نسبت دهیم صرف نظر از هر چیزی، کنترل ScriptManager از نسخه MicrosoftAJAX.debug.js. استفاده می نماید.
پیشنهاد می کنم که اگر وب سایت شما از لحاظ اسکریپتی دچار مشکل نیست، حتما مقدار ScriptManager =Release را برای این کنترل انتخاب نمایید. این موضوع به میزان زیادی در کارایی صفحات نقش دارد.


<asp:ScriptManager ID="ScriptManager1" ScriptMode="Release" ></asp:ScriptManager>

ضمنا به یاد داشته باشید که پس از اولین باری که صفحه لود شود، اسکریپت های لود شده، در حافظه مرورگر Cache می شوند.
خصوصیت مهم دیگری که به بررسی آن می پردازم، LoadScriptsBeforeUI می باشد.
شاید بدترین مشکلی که در مورد استفاده از جاوا اسکریپت در صفحات وب وجود داشته باشد، زمان لود فایل های جاوا اسکریپت می باشد. هنگام لود فایل های جاوا اسکریپت در حقیقت لود سایر عناصر صفحه متوقف می شود و در صورتی که این اسکریپت ها در ابتدای صفحه قرار داشته  باشند، بازدید کنندگان سایت با صفحه ای سفید روبرو می شوند و تا زمان لود کامل اسکریپت ها این قضیه ادامه دارد. و پس از لود اسکریپت ها ، سایر عناصر HTML از قبلی متن ها و عکس ها شروع به لود شدن می کنند.
این مشکل در ASP.NET AJAX به این علت به وجود می آید که به طور پیشفرض، اسکریپت ها و منابع مورد نیاز ASP.NET و  ASP.NET AJAX و AjaxControlToolkit و سایر Extender ها دقیقا پس از شروع تگ form قرار می گیرند و درنتیجه ابتدا کلیه این اسکریپت ها و منابع باید لود شوند تا نوبت به سایر عناصر صفحه برسد.
شکل زیر بیانگر این مطلب می باشد.

همانطور که در تصویر بالا ملاحظه می کنید، بسیار از اسکریپت ها دقیقا بعد از تگ form لود خواهند شد و همان مشکلی که در بالا ذکر شد، به وجود می آید.
راه حل این مشکل لود اسکریپت ها بعد از لود سایر عناصر صفحه می باشد و بهترین مکان برای اینکار، دقیقا قبل از بسته شده تگ body در انتهای صفحه می باشد.
البته با توجه به سیاست های سایت و بسیاری از عوامل دیگر، شاید شما نیاز داشته باشید که یک اسکریپت حتما در ابتدای صفحه لود شود  (به همین دلیل در ابتدای مقاله ذکر کردم که با توجه به بسیاری از عوامل باید تصمیم گرفت!)
ولی در غالب موارد این موضوع مشکل خاصی به وجود نمی آورد و با انتقال اسکریپت ها به انتهای صفحه می توانید راندامان و سرعت لود صفحه را چندین برابر بالا ببریم.

تذکر :

  • برخی اسکریپت ها (بخصوص اسکریت های مربوط به کنترل های AjaxControlToolkit) جهت ارسال کنترل های صفحه به مکان های مناسب خود استفاده می شوند و به همین دلیل باید در ابتدای صفحه لود شوند. در غیر اینصورت تا زمانی که صفحه به طور کامل لود نشده است، کنترل مورد نظر در محل مناسب خود قرار نمی گیرد. به طور مثال کنترل AlwaysVisibleControlExtender از اینگونه کنترل ها می باشد. به این دلیل توصیه می شود که مکان (position) ابتدایی این کنترل ها را در صفحه به طور صریح به شکل Relative یا absolute مشخص کنید.

  • در مورد اسکریپت هایی که خود نیز قصد داریم به شکل یک فایل خارجی (مثلا Sample.js) به صفحه اضافه کنیم ، نیز بهتر است در انتهای صفحه قرار بگیرند.

کنترل ScriptManager دارای صفتی به نام LoadScriptsBeforeUI می باشد که مقدار پیشفرض آن true می باشد. همانطور که از نام این صفت پیداست ، هنگامی که مقدار آن true باشد، اغلب  اسکریپت های مربوط به  ASP.NET AJAX را در ابتدای صفحه لود می کند. برای اینکه این اسکرپت ها را به انتهای صفحه انتقال دهیم باید مقدار این صفت را false کنیم.


<asp:ScriptManager ID="ScriptManager1" ScriptMode="Release" LoadScriptsBeforeUI="false" />

با انجام این کار مقداری از اسکریپت ها به انتهای صفحه منتقل می شوند ولی متاسفانه بسیاری از اسکریپت ها همچنان در ابتدای صفحه باقی می مانند.
دلیل این امر این است که این اسکرپت ها توسط Page.ClientScript.RegisterClientScriptBlock رجیستر شده اند. کلاس Page داخل فضای نامی System.Web می باشد و دارای متدی به نام BeginFormRender می باشد. در داخل این متد، Client Script Block ها رندر می شوند. و این متد اسکریپت هایی را که رندر می کند، دقیقا بعد از تگ form در ابتدا صفحه قرار می دهد.
در شکل زیر شمای کلی این متد را ملاحظه می نمایید.


internal void BeginFormRender(HtmlTextWriter writer, string formUniqueID)

{

   ...

        this.ClientScript.RenderHiddenFields(writer);

        this.RenderViewStateFields(writer);

        ...

        if (this.ClientSupportsJavaScript)

        {

            ...

            if (this._fRequirePostBackScript)

            {

                this.RenderPostBackScript(writer, formUniqueID);

            }

            if (this._fRequireWebFormsScript)

            {

                this.RenderWebFormsScript(writer);

            }

        }

        this.ClientScript.RenderClientScriptBlocks(writer);

}

همانطور که ملاحظه می کنید این متد به شکل internal تعریف شده و قابل override شدن نیز نمی باشد. پس چگونه می توان این مشکل را حل نمود؟
راه حل این موضوع خارج از محدوده این مقاله می باشد ولی در صورتی که علاقه مند می باشید، می توانید یک مقاله عالی در این زمینه از آقای Omar Al Zabir را مطالعه کنید.

UpdatePanel:

صحبتی که در ابتدای مقاله در مورد آسان نمودن تکنولوژی های پیچیده نمودم، در مورد کنترل UpdatePanel کاملا صادق می باشد. عملکرد پشت صحنه این کنترل بسیار پیچیده می باشد ولی نحوه استفاده از آن بسیار آسان.
قبل از اینکه به بررسی نکات موجود در مورد UpdatePanel بپردازم، مختصری در مورد نحوه عملکرد آن صحبت می کنم.
هنگامی که یکی از کنترل های موجود در UpdatePanel درخواست  Postback می کند یا به عبارت بهتری UpdatePanel را  تریگر (Trigger) می کند، UpdatePanel محتوای خود را آپدیت می کند. بدین شکل که ابتدا محتوای کل ViewState صفحه را به سمت سرور ارسال می کند و پس از اینکه عملیات در سمت سرور به پایان رسید، مقدار ViewState جدید کل صفحه را به همراه محتویات جدید خود دریافت می کند.
با توجه به اینکه معمولا در صفحات وب، حجم عظیمی از ViewState تولید می شود، پس ارسال و دریافت این مقدار اطلاعات می تواند چیزی شبیه فاجعه به بار بیاورد.
به این دلیل پیشنهاد می شود که به UpdatePanel به عنوان آخرین راه حل نگاه کنید و نه اولین!
برای اطلاع بیشتر پیشنهاد می کنم  این مقاله کوتاه و با ارزش را نیز مطالعه نمایید.
ولی سهولت بالای استفاده از این کنترل، عدم استفاده از آن را غیر ممکن نموده است و بنده در اینجا به معرفی برخی روش ها جهت بالا بردن راندمان آن می پردازم.
اولین موردی که باید بررسی شود، خصوصیت UpdateMode می باشد.
اگر چند UpdatePanel در صفحه داشته باشیم، هنگامی که محتوای یکی از آنها آپدیت می شود، به طور پیشفرض سایر UpdatePanel ها نیز محتوای خود را بروزرسانی می کنند. دلیل این امر همین خصوصیت UpdateMode است که مقدار پیشفرض آن Always می باشد.
به یاد داشته باشید که اولین کاری که در مورد UpdatePanel انجام می دهید این باشد که مقدار این خصوصیت را برای Conditional قرار دهید.


<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional"  >
   <ContentTemplate>
   <ContentTemplate>
</asp:UpdatePanel>

با توجه به اینکه هنگامی که UpdatePanel تریگر می شود، تمام محتویات جدید خود را از سرور دریافت نموده و بروز رسانی می نماید، لذا سعی کنید که تعداد کنترل هایی که داخل UpdatePanel قرار می گیرند، حد اقل باشند. برای انجام این کار، کنترل هایی را که قرار است بروز رسانی شوند را داخل UpdatePanel قرار داده و کنترل هایی که دستور بروزرسانی را می دهند ،توسط  AsyncPostBackTrigger در داخل UpdatePanel رجیستر شوند.
تا جایی که می توانید و به کار شما خدشه ای وارد نمی کند، سعی کنید خصوصیت EnableViewState کنترل های صفحه را برابر false قرار دهید.
یکی از معمول ترین استفاده هایی که از UpdatePanel می شود، قرار دادن کنترل GridView داخل آن می باشد. پس از انجام این کار، می توانیم عمل Paging را بدون انجام Postback کل صفحه، انجام دهیم.
کنترل GridView یکی از کنترل هایی است به مقدار بسیار زیادی ViewState تولید می کند. برای رفع این مشکل پیشنهاد می شود که حتما مقدار خصوصیت EnableViewState مربوط به این کنترل را برابر false قرار دهید. تنها مشکلی که این موضوع می تواند به وجود آورد این است که اگر صفحه Postback شود این کنترل مقادیر خود را از دست می دهد. برای رفع این مشکل پیشنهاد می شود که هنگامی که محتوای این کنترل را از دیتابیس برای اولین بار بازیابی نمودید، باید اطلاعات را Cache کنید تا در هنگام عمل Postback یا انجام عمل Paging، اطلاعات از حافظه Cache خوانده شوند و نه از دیتابیس.
امیدوارم نکات ذکر شده در این مقاله مورد استفاده شما قرار گرفته باشد.