通过异步页面内容装载提升ASP.NET页面反应速度

原文:Boost ASP.NET performance with deferred content loading

翻译:南卓铜 ([email protected])

clip_image002[4]

在设计一个ASP.NET Web页面时,其反应速度取决于各组成部分的性能,比如在上图,红色条所在的GetRSSReader(从其它网站上读取RSS)功能会导致整个页面反应速度很慢。不管你如何去优化该页面的其它部分,只有其中有一部分反应慢就会导致用户感觉整个Web页面速度呆滞。

在本文,我将给大家演示一种规避这个问题的方法。通过将内容放置到用户控件(User control),直到整个核心内容都显示完后才去装载用户控件内容,这样就可以大幅提升可观察的性能。

我们可以将页面内容细致的分解,通过上述方法可以方便的提升应用程序反应速度,这是用户最关心的。包括下面四个步骤:建立用户控件,将用户控件内容输出成HTML(通过Webservice),提供进程指示条,以及应用ASP.NET AJAX请求在客户端插入此HTML。

1. 建立用户控件

首先,我们需要将装载速度慢但不是核心的内容包装在用户控件(User control)。在这个例子里,我们实现一个简单的RSS聚合阅读器来显示最新的用户帖子。

这里的关键是获取RSS聚合的基本信息。我在这里使用ASP.NET 3.5的一个新功能:LINQ to XML。LINQ使得读取关系数据库、XML等数据源的繁杂工作大为简化。我每次使用它都心动不已。(译者注,不懂LINQ或者ASP.NET 3.5并不会妨碍理解这里讲述的方法)

protected void Page_Load(object sender, EventArgs e)
{
  XDocument feedXML = 
    XDocument.Load("http://feeds.encosia.com/Encosia");
  var feeds = from feed in feedXML.Descendants("item")
              select new
              {
                Title = feed.Element("title").Value,
                Link = feed.Element("link").Value,
                Description = feed.Element("description").Value
              };
  PostList.DataSource = feeds;
  PostList.DataBind();
}

使用ASP.NET 3.5的另一个新控件 ListView来显示聚合的内容。(译者注,可以不管ASP.NET 3.5,这里仅是一个User control的例子。)

<asp:ListView runat="server" ID="PostList">
  <LayoutTemplate>
    <ul>
      <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
    </ul>
  </LayoutTemplate>
  <ItemTemplate>
    <li><a href='<%# Eval("Link") %>'><%# Eval("Title") %></a><br />
      <%# Eval("Description") %>         
    </li>
  </ItemTemplate>
</asp:ListView>

通过使用一点CSS(包括在源代码,在下面可以下载),聚合的结果可以很好的显示出来,如下图。

clip_image004[4]

ListView可以很方便的演示下面步骤,因为通过它,我们基本不需要太多的代码就可以生成HTML,最后将这些生成的HTML代码插入到页面。

2. 将用户控件润色成HTML

本步我们创建一个Web service将用户控件生成HTML字符串。这里,我们需要在ASP.NET页面实例之外生成HTML字符串。一般情况下,用户控件都是被装载到Page实例上。

为解决这个问题,我们可以创建一个临时的ASP.NET Page类,动态加载用户控件,然后在Web service里执行它。实际实现比起描述要简单易懂的多。

[WebMethod]
public string GetRSSReader()
{
  // 创建新Page类,并加载用户控件
  Page page = new Page();
  UserControl ctl =
    (UserControl)page.LoadControl("~/RSSReaderControl.ascx");
  page.Controls.Add(ctl);
 
  //将动态页生成HTML
  StringWriter writer = new StringWriter();
  HttpContext.Current.Server.Execute(page, writer, false);
 
  //生成的HTML返回为字符串
  return writer.ToString();
}

你可能在担心创建一个新的页面实例是否会有性能上的影响。一开始,我也是这么考虑的。但,因为我们的Page实例是创建在Web service上,而不是在ASP.NET HTTP管道(pipeline)上,而且只包括一个用户控件,此额外的开支可以被忽略不计。Page实例本身的开支相对于整个HTTP进程来讲是微不足道的。

3. 创建演示页面

我们需要一个演示页面来快速显示核心内容。在该页上,定义一个DIV标签。该标签在核心内容显示完后再异步从服务器端装载内容。

<asp:ScriptManager runat="server">
  <Services>
    <asp:ServiceReference Path="~/RSSReader.asmx" />
  </Services>
  <Scripts>
    <asp:ScriptReference Path="~/Default.js" />
  </Scripts>
</asp:ScriptManager>
<div id="Container">
  <div id="RSSBlock" class="loading"></div>
  <div id="Content">
    <p>Lorem ipsum dolor sit amet, consectetuer adipiscing...</p>
  </div>
</div>

如你看着的,RSSBlock定义的这个DIV标签分配有一个CSS类“loading”。这个CSS类显示进度指示条,一直到异步加载的内容被下载到客户端。

.loading { 
  background: url('progress-indicator.gif') no-repeat center; 
}

clip_image006[4]

所以,这里其实不是一个真实的指示条,无法计算进程进度。但用户是无法知道这是不是真实的。你不说没人会知道。

4. 从Javascript里调用Web service

现在我们已经有了一个空位置,我们需要将真实的HTML填充这个位置。ASP.NET AJAX为我们做好了大部分的事情。

Sys.Application.add_init(AppInit);
 
function AppInit() {
  RSSReader.GetRSSReader(OnSuccess, OnFailure);
}
 
function OnSuccess(result) {
  // .loading CSS类从div上移去,效果上看是移去了进程条
  Sys.UI.DomElement.removeCssClass($get('RSSBlock'), 'loading');
 
  // 将生成的HTML填充这个div位置
  $get('RSSBlock').innerHTML = result;
}
 
function OnFailure() {
  // 如果失败了,要做点什么。比如重试,等
}

因为这里我们用了CSS类来实现进度条,只要简单移去该loading类就可以了。这里我们使用removeCssClass方法。更多关于该方法的信息,可以见这里

动画的背景移去后,是时候在div中插入HTML内容了。最终的结果正是我们期待的,前面我们设计的用户控件已经显示在div指定的位置上了,而且不会妨碍到整个页面的反应速度。

5. 结论

我想大家可能发现这个方法是很有用的。它可以让你利用现有的ASP.NET知识,结合服务器控件,实现一个轻量级的基于AJAX的模板方案。同时,它使一些繁琐、不易维护的工作变得简单。

注意我们这里没有使用UpdatePanel。使用以上描述的技术,不需要使用Partial Postback。它不仅可以提升性能,而且即使在内容延后被装载的时候,也不影响页面其它使用了UpdatePanel的正常工作。

源码

为奥运让路

就转一则通知,不想评论任何东西。

>中科院植物所关于奥运会期间停止同位素实验的通知

>根据《海淀区2008年放射物品专项管理工作方案》的规定,为确保奥运期间
>我单位放射物品绝对安全,要求各单位在奥运期间(7月1日—10月8日)停止使
>用同位素实验室。

>请需要进行同位素实验的同志提前做好准备工作。由此带来的不便之处,请
>大家给与谅解。

>综合办公室
>二OO八年二月十四日

Group meeting有关multifractal云里雾里的

在Group meeting上给大家演示用multifractal+wavelet的方法做time-space downscaling。讲的稀里糊涂,听的也是云里雾里。其实在看的时候就有好多问题发现,但没有时间进一步去看相关文献。L老师提的问题又太过涉及公式本身。
不过这个paper proposed的方法估计本身也有问题,尽管结论说downscale还不错。但作者在此文发表后的后续工作又重新time和space分开来做downscaling了,估计也是意识到time和space结合在一起很难找到完美的方法。

送朵朵去幼儿园了

这两天外面的雪好大。今天送朵朵到附近的一个 Children Learning & Development Center。
看样子还不错。只是太贵,一个月要600多了,一合人民币更是高的离谱。
没法子,这样才能腾出一点时间。

同事聚会

周日几个同事朋友带家里领导到China Star小聚了一把,十分高兴
平时出来的机会不多。不象国内,时不时能出来坐坐。

SPIE Conference OP.405 and its Special Session on Operational Satellite Observations of Land Surface

Dear Land Remote Sensing Colleague/Enthusiastic:

You are specially
invited to participate in the SPIE Conference Special Session on "Operational
Satellite Observations of Land Surface Properties and their Scientific and
Societal Applications". The SPIE 2008 Annual Meeting will be held during
August 10-14, 2008 at
San Diego Convention Center, San Diego, CA,
USA. Abstract due date is January 28, 2008.  Please
see the attached announcement for more information. The conference information
and abstract submission website is

Click here to see details

If
you have any further questions about the special session, please contact any of
us: Bob Yu at [email protected], Cheng-Zhi Zou at [email protected], Jeff Privette
at [email protected], or Jerry Zhan
at [email protected].

We look forward to your participation and seeing you in
San Diego, California in August

2008!Organizer: Jerry Zhan, Bob Yu, Cheng-Zhi Zou
and Jeff Privette.

Firefox下Live ID登录问题

Live Messenger我更新成8.5,自动给安装了Live Sign-in Assistant。用IE时可以自动登录Passport,挺方便。但在Firefox下发现需要两次密码才能登录。第一次总是提示说错误(我确认密码是对的)。Google也检索不到答案。
我第一感觉是否中木马了。对机器进行了仔细的检查,应该不是。
所以这里报告一下,有人有类似的问题吗?

这里没有假期

春晚看起来又是一片歌舞升平,皆大欢喜。前面瞅了一眼那个军嫂的小品,决定不再看了
这里冷冷清清的,老板也不给放假,得照样上班。
祝大家节日快乐