优化页面加载速度:异步加载数据的实践指南

在开发网页应用时,经常会遇到页面加载缓慢的问题。例如,一个网页开始显示,但下拉菜单显示不完整,并且页面会卡顿6-7秒,直到数据加载完毕,页面才正确显示。这种情况通常是因为开发者将耗时的代码(如加载SQL Server数据)放在了Page_Load函数中,导致浏览器在数据加载完成之前几乎无法响应。

本文将指导如何通过将耗时的代码移至异步线程,并在数据准备就绪后更新网页,来解决这个问题。

免责声明:使用现代技术如Angular加载和显示数据无疑更加高效和易于维护,本文旨在提供一个简单的步骤指南,以快速改进旧版页面,而无需重写所有代码。

旧版代码示例

开发者将从SQL Server加载数据的代码放在了Page_Load函数中。通过创建一个10秒的延迟,然后生成一个包含样本数据的DataTable,并将其设置为DataGrid的数据源,来模拟这个问题。

protected void Page_Load(object sender, EventArgs e) { if (IsPostBack) return; // 等待10秒... System.Threading.Thread.Sleep(10000); // ...然后创建一个包含样本数据的DataTable... 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, "James", "Spencer", "M", new DateTime(1962, 3, 19)}); dt.Rows.Add(new object[] {2, "Edward", "Jones", "M", new DateTime(1939, 7, 12)}); dt.Rows.Add(new object[] {3, "Janet", "Spender", "F", new DateTime(1996, 1, 7)}); dt.Rows.Add(new object[] {4, "Maria", "Percy", "F", null}); dt.Rows.Add(new object[] {5, "Malcolm", "Marvelous", "M", new DateTime(1973, 5, 7)}); // ...并将其绑定到ASP.Net GridView控件。 this.grid.DataSource = dt; this.grid.DataBind(); }

这段代码的结果是网页加载非常缓慢。通常浏览器在显示页面的过程中会卡顿几秒钟,然后才能显示完整的网页。

使加载过程异步

首先,需要在.aspx文件中找到包含需要更新的控件的部分。在示例中,只有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" /> <asp:DataGrid ID="grid" runat="server"> </asp:DataGrid> </ContentTemplate> </asp:UpdatePanel>

目标是尽快将网页显示在屏幕上,一旦数据加载完成,就可以回去更新网页的这一部分。

接下来,需要将数据加载代码从Page_Load函数中分离出来,放入自己的函数中,并使其填充一个变量(在本例中为DataTable),该变量存储在Session变量中。

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() { // (这将是从某个web服务加载数据的耗时函数) // 等待10秒... System.Threading.Thread.Sleep(10000); // ...然后创建一个包含样本数据的DataTable... dt = new System.Data.DataTable("Drivers"); // ... // 一旦所有数据加载完成,设置这个布尔变量,将触发DataGrid控件显示新加载的数据。 bReadyToDisplayData = true; }

这看起来更好,但仍然同步调用数据加载函数,所以接下来,让改变Page_Load以异步调用它。

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

最后,需要添加一个Timer "tick"处理程序来将所有内容联系起来。

protected void timer_tick(object sender, EventArgs e) { // 每秒,网页将调用这个函数。 if (bReadyToDisplayData == false) { return; // 后台线程仍在运行。 } // 数据已经加载完成! // 使用JSON数据填充Grid this.grid.DataSource = dt; this.grid.DataBind(); // 现在可以更新UpdatePanel,并停止计时器。网页现在完成了! this.panel.Update(); MyTimer.Enabled = false; }

就是这样!现在,当打开这个aspx网页时,它会非常快地显示出来,然后去加载它的数据,当它完成后,将设置DataGrid的DataSource指向这些数据,并让它显示出来。

关于使用Session变量的说明

如果发现这段代码对不起作用,请检查.aspx页面是否能够保存Session变量的值。要做到这一点,在Page_Load函数中设置bReadyToDisplayData变量后放置一个断点。

protected void Page_Load(object sender, EventArgs e) { if (IsPostBack) return; bReadyToDisplayData = false; // 在下一行放置一个断点... System.Threading.Thread thread = new System.Threading.Thread(LoadSomeData); // 如果然后检查Session变量,它的"Count"值应该至少为1(因为刚刚添加了一个Session变量来存储bReadyToDisplayData变量)。 // 如果这个"Count"值为0,那么网页没有存储Session变量,这段代码将无法正常工作。

需要检查的两件事:

  • 服务器名称是否包含下划线字符?这可能会导致IIS出现问题。
  • 尝试在Global.asax文件中添加以下几行:
protected void Session_Load(object sender, EventArgs e) { Session["info"] = 1; }

这个Session变量问题似乎主要在Internet Explorer 11上被注意到。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485