بهبود زمان بارگذاری صفحات در Asp.Net

چهارشنبه 29 اردیبهشت 1395

در این مقاله قصد داریم راه حل هایی برای رفع مشکل صفحات ASP بیان کنیم که هنگام شروع بهم ریخته و نامرتب نشان داده نشوند. حتما برای شما هم اتفاق افتاده است که در هنگام باز کردن یک سایت ، منو ها در وسط صفحه نمایش ،کشیده شده اند و بعد از 6-7 ثانیه صفحه مرتب شده و بدرستی نمایش داده می شود.

بهبود زمان بارگذاری صفحات در Asp.Net

حتما برای شما هم اتفاق افتاده است که در هنگام باز کردن یک سایت ، منو ها در وسط صفحه نمایش ،کشیده شده اند و بعد از 6-7 ثانیه صفحه مرتب شده و بدرستی نمایش داده می شود.

گاهی اوقات برنامه نویسان تصمیم میگیرند که تمام کدهایی که زمانی را برای بارگذاری داده های SQL Server مصرف میکنند درون تابع  Page_Load قرار دهند. و یکبار که اجرا شروع شد، مرورگر تا زمانی که بارگذاری داده ها پایان یابد مکث میکند. در این مقاله برای رفع این مشکلات ، کدهای مصرف زمان را در thread جداگانه ای قرار می دهیم و هنگامی که داده ها آماده است، Webpage  آپدیت خواهد شد. 

اگر از تکنولوژیهایی مانند  Angular  برای بارگذاری و نمایش داده ها استفاده شود بسیار کارامدتر است. اما این مقاله راه ساده ای را برای حل مشکل این صفحات بدون نیاز به دوباره نوشتن کدهای برنامه خود است.

به طور مثال کد زیر را در نظر بگیرید. برنامه نویس کدها را برای بارگذاری داده ها از SQL server  درون تابع  Page_Load  قرار داده است.

این مشکل را با ایجاد یک توقف 10 ثانیه ای شبیه سازی میکنیم. سپس یک نمونه DataTable را تولید کرده و آن را به عنوان  Data Source  برای  DataGrid  قرار می دهد.

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
        return;

    //  Wait for 10 seconds...
    System.Threading.Thread.Sleep(10000);

    //  .. then create a DataTable containing some sample data...
    System.Data.DataTable dt = new System.Data.DataTable("Drivers");

    dt.Columns.Add("UserID", Type.GetType("System.Int64"));
    dt.Columns.Add("Surname", Type.GetType("System.String"));
    dt.Columns.Add("Forename", Type.GetType("System.String"));
    dt.Columns.Add("Sex", Type.GetType("System.String"));
    dt.Columns.Add("Date of Birth", Type.GetType("System.DateTime"));

    dt.Rows.Add(new object[] { 1, "علی", "علایی", "M", new DateTime(1962, 3, 19) });
    dt.Rows.Add(new object[] { 2, "رضا", "رضایی", "M", new DateTime(1939, 7, 12) });
    dt.Rows.Add(new object[] { 3, "امید", "علایی", "M", new DateTime(1996, 1, 7) });
    dt.Rows.Add(new object[] { 4, "مریم", "رضایی", "F", null });
    dt.Rows.Add(new object[] { 5, "ماکان", "غلامی", "M", new DateTime(1973, 5, 7) });

    //  ...and bind it to our ASP.Net GridView control.
    this.grid.DataSource = dt;
    this.grid.DataBind();
}

نتیجه این کد این است که WebPage بسیار کند نمایش داده می شود. مرورگرها معمولا از صفحات نمایشی دور هستند پس چند ثانیه قبل از مدیریت نهایی برای نمایش WebPage تکمیل شده متوقف می شوند.

برای بهبود و همگام سازی آن ابتدا به فایل با پسوند aspx. رفته و به سراغ بخشی از  Webpage  که شامل کنترلهایی است که میخواهید زمانی که کار time-consuming به اتمام رسید آپدیت شود می رویم. در مثال ما فقط DataGrid ، هنگامی که داده ها بارگذاری شدند نیاز به آپدیت دارد.

<asp:DataGrid ID="grid" runat="server"></asp:DataGrid>

باید این کنترل را درون یک  UpdatePanel و ContentTemplate قرار دهیم و برای آن یک کنترل  Timer در نظر بگیریم.

<asp:UpdatePanel ID="panel" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <asp:Timer ID="MyTimer" OnTick="timer_tick" Interval="1000" runat="server" />



        <!--  Put your controls that you will need updating, here.. -->
        <asp:DataGrid ID="grid" runat="server"></asp:DataGrid>



    </ContentTemplate>
</asp:UpdatePanel>

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

قدم بعدی جدا کردن کدهای  data-loading از تابع  Page_Load  است، و برای این کار یک متغیر (در اینجا  DataTable) که در یک  Session Variable ذخیره شده است را پر میکنیم.

یکی از این متغیرهای  session را برای هر تکه از داده هایی که به طور ناهمزمان بارگذاری خواهیم کرد نیاز داریم.

همچنین به یک متغیر Session (در اینجا  bReadyToDisplayData ) از نوع  boolean  احتیاج داریم که هنگام پایان یافتن بارگذاری داده به صورت  true  تنظیم شود.

System.Data.DataTable dt
{
    get
    {
        return (System.Data.DataTable)Session["table1"];
    }
    set
    {
        Session["table1"] = value;
    }
}
bool bReadyToDisplayData
{
    get
    {
        return (bool)Session["bReadyToDisplayData"];
    }
    set
    {
        Session["bReadyToDisplayData"] = value;
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
        return;

   bReadyToDisplayData = false;

   LoadDataFromWebService();
}

private void LoadDataFromWebService()
{
    //  (This would be our time-consuming function which loads data from some web service.)

    //  Wait for 10 seconds...
    System.Threading.Thread.Sleep(10000);

    //  .. then create a DataTable containing some sample data...
    dt = new System.Data.DataTable("Drivers");

    //  ... etc ...


    //  Note: We no longer bind our DataTable to our control in this function.


    //  Once all of our data has been loaded, we set this boolean variable, which will
    //  trigger our DataGrid controls to be displayed, showing our freshly-loaded data.
    bReadyToDisplayData = true;
}

کمی بهتر شد اما هنوز تابع data-loading به صورت همزمان فراخوانی می شود. پس  Page_Load را برای فراخوانی آن به صورت غیر همزمان تغییر می دهیم.

 

System.Threading.Thread thread = new System.Threading.Thread(LoadDataFromWebService);
thread.Start();

 

برای ارتباط همه اینها با هم یک چیز دیگر نیز باید اضافه شود. همانطور که میدانید یک کنترل  Timer اضافه کردیم که به ما اجازه می دهد در فواصل معین بررسی کنیم که آیا بارگذاری داده ها به پایان رسیده است و چه زمانی پر کردن کنترل grid  به پایان می رسد. برای این کار به یک handler برای Timer با نام tick نیاز داریم.  بدون این متغیر  Timer نمی توانیم متدی از آپدیت یا  UpdatePanel را داشته باشیم.

protected void timer_tick(object sender, EventArgs e)
{
    //  Every second, our webpage will call this function.
    //  If our background thread to load some JSON data has finished running, then 
    //  we'll want to display the data in a grid, and can then stop the timer.
    //
    if (bReadyToDisplayData == false)
    {
        return;     //  Our background thread is still running.
    }


    //  Our JSON data has finished loading !


    //  Populate our Grid with the JSON data
    this.grid.DataSource = dt;
    this.grid.DataBind();

    //  We can now update our UpdatePanel, and stop the timer.  Our webpage is now complete!
    this.panel.Update();                
    MyTimer.Enabled = false;
}

اکنون اگر این صفحه را باز کنیم، به سرعت نمایش داده می شود و پس از آن داده ها بارگذاری می شوند و از پایان بارگذاری ،  Datasource متعلق به Datagird به این داده ها اشاره میکند و آنها را به نمایش می گذارد.

فقط در استفاده از متغیرهای Session به یک نکته توجه داشته باشید . اگر دریابید که این کد برای شما کار نمیکند، صفحه aspx. خود را برای مدیریت ذخیره مقادیر متغیرهای  Session چک کنید. برای این کار یک  breakpoint در تابع Page_Load خود قرار دهید درست بعد از جایی که متغیر bReadyToDisplayData بکار رفته است.

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
        return;

    bReadyToDisplayData = false;

    //  Put a breakpoint on the following line...
    System.Threading.Thread thread = new System.Threading.Thread(LoadSomeData);

 

پس از بررسی متغیر  Session مقدار آن باید حداقل  1 باشد.

اگر مقدار آن 0 بود،  Webpage شما متغیرهای Session را ذخیره نکرده است و این کد به درستی کار نمیکند.

دو چیز باید بررسی شود :

1. آیا نام  server شما شامل کاراکترهای زیر خط دار است؟ ظاهرا این باعث بروز مشکلی با  IIS خواهد شد.

2. کد زیر را در فایل  Global.asax اضافه کنید.

protected void Session_Load(object sender, EventArgs e)
{
    Session["info"] = 1;
}

به این مشکل متغیر  Session  بیشتر در internet Explorer 11 توجه شده است .

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید