速度的刺激:托管 AJAX 能否让 Web 应用程序提速?
Posted 微软中国MSDN
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了速度的刺激:托管 AJAX 能否让 Web 应用程序提速?相关的知识,希望对你有一定的参考价值。
有关本主题的多项研究表明,创建 AJAX Web 应用程序时遇到的两个最重要问题是,运行速度和响应速度。这可能是一些开发者选择创建原生应用程序(而不是 Web 应用程序)的部分原因所在。
但如果我说有一种方法可以创建运行速度和响应速度比现有应用程序快 100 倍的 AJAX Web 应用程序,又如何呢?
我发明了一种方法,用于创建基于 javascript 的纯正 AJAX Web 应用程序,至少可以将应用程序的带宽使用降低 10 倍,有时降幅可达 300 倍之多,具体视要使用的工具类型及要创建的内容而定。我将此技术称为“托管 AJAX”。
在某种程度上,我是受到 Microsoft 生成公共语言运行时 (CLR) 的方式启发,发明了托管 AJAX。例如,在用户创建 C# 应用程序时,编译器会创建 CLR 程序集。这意味着,最终结果的运行时环境是“托管环境”。
创建托管 AJAX 应用程序时,最终的编译结果只会是普通的 ASP.NET 网站;它会变成托管环境,其中最终结果的 JavaScript 部分会被完全抽取出来,操作方式与拥有 CLR 程序集时将 CPU 指令抽取出来一样。
这是如何实现的呢?
几乎不需要掌握任何新知识,即可使用托管 AJAX。如果已完成任一 ASP.NET 开发,可以将新的控件库拖到 .aspx 页面,再继续完成工作,操作方式几乎与之前完全相同。
在 .aspx 标记或 C#/F#/Visual Basic .NET 代码隐藏页面中创建几个 ASP.NE 控件。然后,修饰这些控件的属性,并添加几个 AJAX 事件处理程序,这样就大功告成了!
初始呈现生成的是普通旧 html。不过,在 AJAX 请求期间在服务器端对任意控件做出的所有更改,都会以 JSON 的形式传递到客户端。
因此,客户端可以获得总大小不到 5KB 的微型 JavaScript 库,用户可以创建各种 AJAX 控件(如 TreeView、DataGrid 和 TabView),从来都不需要使用超过 5KB 的 JavaScript。
此时便会发现,已超出用作独立 JavaScript 文件的 jQuery 几乎一个数量级(缩小和 Zopfli 压缩后的 jQuery 版本 2.1.3 为 30KB)。因此,只在页面上添加 jQuery,而不添加其他任何 JavaScript,带宽使用已是使用托管 AJAX 方法时的 6 倍。开始在自己的 JavaScript 中使用 jQuery 时,此数值就会猛增。
拉取缩小和压缩版本的 jQuery UI 会导致 JavaScript 部分增加 73.5KB。只在页面上添加 jQuery 和 jQuery UI,大小会再增加 103.4KB(用 103.4KB 除以 4.8KB,可以得出带宽消耗增大了 21.5 倍)。
此时,仍尚未在页面上创建任何 UI 元素,但 jQuery 和 jQuery UI 占用的空间就几乎是托管 AJAX 方法的 22 倍。使用这 5KB 的 JavaScript,可以创建几乎所有梦寐以求的 UI 小组件,包括 jQuery 和 jQuery UI 可以创建的大部分 UI 控件。
无论执行哪种操作,基本上很少会(如果有过)超过这 5KB 的 JavaScript 限制。应用程序的其他部分(如 HTML 和 CSS)也可能会变小很多。
使用这种方法,可以创建各种 AJAX UI 控件,如 AJAX TreeView 控件、DataGrid 控件和 TabView 控件。而且,创建这些小组件时,永远都不需要额外添加 JavaScript。此外,无需掌握任何新知识,即可使用这些控件。它们的使用方法(几乎)与在 ASP.NET 中使用传统 WebControl 的方法相同。
托管 AJAX 方法提供两种不同的方式,用于处理页面收到的 HTTP 请求。一种处理程序是普通 HTTP 请求,可直接向客户端提供 HTML。另一种处理程序支持检查是否有 HTTP POST 参数。
若有此参数,处理程序只会以 JSON 形式将各个控件的更改重新呈现给客户端。在 AJAX 请求期间,将会自动重新创建通过修改页面的控件层次结构而创建的所有控件,其中包含旧请求内的属性。
客户端上有一个常规处理程序,可处理控件的 JSON 属性,一般会更新客户端上 DOM 元素的属性和 DOM 事件处理程序。
这种方法带来了许多积极影响,如可以直接按原样呈现 HTML 元素,这样就不会干扰 Web 的最初创建方式了。这意味着,Web 应用程序在语义上变得更易于理解(例如,被搜索引擎蜘蛛程序理解)。此外,若要做到尽善尽美,它还可以创建一个优质环境,用于实际修改客户端上的内容。
仍可以根据需要将这种方法与任意数量的自定义 JavaScript 结合使用。在这种情况下,只需检查普通 HTML 请求中呈现的 HTML 即可。比较这种方法与其他许多 AJAX UI 库(通常包含许多兆字节的 JavaScript,用于创建 DataGrid 和 TreeView)使用的“神奇 div”方法。
这样,就可以理解运行速度和响应速度快 100 倍并不是夸大其词。实际上,相较于与 C# 和 ASP.NET 结合使用的所有最常用组件 UI 工具包,在带宽消耗方面,它的运行速度和响应速度通常可快 100 倍到 250 倍。
我最近测量了 System42 中的托管 AJAX TreeView 小组件与 ASP.NET 堆栈上的三个最大组件工具包的性能值。我发现,在带宽消耗方面,运行速度和响应速度的差异介于 150 倍到 220 倍之间。
为了能够理解这其中的真正含义,假设 Internet 连接速度极慢,需要一秒才能下载 5KB 的 JavaScript。这意味着,一秒就可以下载托管 AJAX JavaScript;若要下载其他一些工具包的 JavaScript 部分,可能需要长达 3 分 40 秒之久。如果使用这两种方法生成两个电子商务解决方案,在转换方面,无需多言,就可以想象差异是多么巨大。
代码展示
好了,闲话少说,接下来将做些实际工作。首先,从 bit.ly/2u5W0EO 下载 Phosphorus Five。接下来,打开 p5.sln 文件,并生成 Phosphorus Five,以便可以转到 p5.ajax.dll 程序集。
由于将在 Web 应用程序中将 p5.ajax.dll 用作引用,因此需要先生成它,然后才能继续操作。请注意,Phosphorus Five 包含超过 30 项目,但在本文中我将重点介绍 p5.ajax 项目。
接下来,在 Visual Studio 中新建一个 ASP.NET 网站。请务必创建 Web 窗体应用程序。在 Visual Studio for Mac 中,可以在“文件 | 新建解决方案 | 其他 | .NET | ASP.NET Web 窗体项目”下找到此应用程序。
在新建的网站中,创建对已生成的 p5.ajax.dll 程序集的引用,并按照如下代码修改 web.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<pages clientIDMode="Static">
<controls>
<add assembly="p5.ajax" namespace="p5.ajax.widgets" tagPrefix="p5" />
</controls>
</pages>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
</configuration>
此代码中最重要的部分是“clientIDMode”和“add assembly”。 此时,可以在 .aspx 标记中使用任意 p5.ajax 控件,只需在它们前面添加前缀 p5 即可。请务必按照图 1 中的代码,修改 Default.aspx 页面的内容。
图 1:创建页面,其中包含一个在获得单击后更改文本的按钮
<%@ Page Language="C#" Inherits="foobar.Default" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Default</title>
</head>
<body>
<form id="form1" runat="server">
<p5:Literal
runat="server"
id="foo"
onclick="foo_onclick"
Element="button">Click me!</p5:Literal>
</form>
</body>
</html>
然后,将它的代码隐藏页面更改为如下所示:
using System;namespace foobar
{ public partial class Default : p5.ajax.core.AjaxPage
{
[p5.ajax.core.WebMethod] public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
{
sender.innerValue = "Hello World from Managed Ajax!";
}
}
}
请注意,必须先从 AjaxPage 继承页面,将 WebMethod 属性添加到事件处理程序,再将事件处理程序的第一个参数专门强类型化为“Literal”小组件。现在,可以启动网站,单击按钮并查看结果。
如果在调试网站时看到不可思议的 bug,请务必禁用 Visual Studio 的“浏览器链接”设置(通常需要单击 Visual Studio 顶部的一个工具栏按钮)。如果对此时出现的情况感到很好奇,请尝试检查 HTTP 请求。此外,还请务必检查它的初始 HTML。
呦,那是怎么回事?
这就是托管 AJAX 的实际效果对于此概念,应注意以下几个要点。首先,可以通过页面中的任意 AJAX 事件处理程序,修改页面上任何控件的所有属性。如果创建了另一 Literal 小组件(例如,“Element”类型“p”),可以通过按钮的“foo_onclick”事件处理程序,更新它的内容。
其次,可以任何认为适当的方式,在小组件中动态添加、删除、更新或检索任意属性。若要引用任意属性或事件处理程序,只需使用 C# 中的下标运算符即可。在图 2 中,没有设置小组件的 innerValue,而是使用 CSS 样式属性,检查它的 style 属性,并切换黄色背景。
请注意,它可以暂留并“记住”小组件的 style 属性。另请注意,这样做并没有在客户端与服务器之间来回传递大量 ViewState。
在实际应用程序中,建议使用 CSS 类。为此,可以将图 2 中的引用从“style”转换为“class”。 不过,我希望保持此示例的简单性,因此并没有混用 CSS 文件,而是为方便起见使用了 style 属性。使用图 2 中的方法,可以根据需要在页面的所有小组件上添加、删除和更改任何属性。
图 2:切换背景色
using System;namespace foobar
{ public partial class Default : p5.ajax.core.AjaxPage
{
[p5.ajax.core.WebMethod] public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
{ if (sender.HasAttribute ("style"))
sender.DeleteAttribute ("style"); else
sender ["style"] = "background-color:Yellow;";
}
}
}
第三(可能也是最重要的一点),可以认为适当的方式,在其他任何小组件中动态添加、删除、更新和插入任意新 AJAX 控件。不过,在介绍这最后一个要点之前,大家需要先检查是否有“三个一组的小组件”。
p5.ajax 中有三个不同的小组件,但它们的 API 非常相似。通过合成将这三个小组件组合在一起后,可以创建任何所需的 HTML 标记。图 2 中的示例使用了 Literal 小组件。Literal 小组件的“innerValue”属性在客户端上映射到“innerHTML”,只允许以字符串或 HTML 的形式更改它的内容。
Container 小组件可以包含小组件。它会记住自己的控件集合,并允许在 AJAX 请求期间动态添加、删除或更改它的控件集合。
第三个小组件是 Void 小组件,专用于不包含任何内容的控件,如 HTML 输入元素、br 元素、hr 元素等。对于此处的示例而言,最重要的一个大概就是 Container 小组件。请继续将 .aspx 页面中的代码更改为图 3 中所示。
图 3:创建包含按钮和项目符号列表(有一个列表项)的页面
<%@ Page Language="C#" Inherits="foobar.Default" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Default</title>
</head>
<body>
<form id="form1" runat="server">
<p5:Literal
runat="server"
id="foo"
onclick="foo_onclick"
Element="button">Click me!</p5:Literal>
<p5:Container
runat="server"
id="bar"
Element="ul">
<p5:Literal
runat="server"
id="initial"
onclick="initial_onclick"
Element="li">Initial list element, try clicking me!</p5:Literal>
</p5:Container>
</form>
</body>
</html>
图 3 中的小组件层次结构将创建一个“button”和一个“ul”元素(其中包含一个“li”子元素)。接下来,按照图 4 中的代码,更改 C# 代码隐藏页面。
图 4:映射 AJAX 事件处理程序以新建列表项
using System;namespace foobar
{ public partial class Default : p5.ajax.core.AjaxPage
{ protected p5.ajax.widgets.Container bar;
[p5.ajax.core.WebMethod] public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
{ // Using the factory method to create a new child widget for our "ul" widget.
var widget = bar.CreatePersistentControl<p5.ajax.widgets.Literal>();
widget.Element = "li";
widget.innerValue = "Try clicking me too!"; // Notice we supply the name of the method below here.
widget ["onclick"] = "secondary_onclick";
}
[p5.ajax.core.WebMethod] public void initial_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
{
sender.innerValue = "I was clicked!";
}
[p5.ajax.core.WebMethod] public void secondary_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
{
sender.innerValue = "I was ALSO clicked!";
}
}
}
请注意,最后一行代码将新的小组件动态插入了 Container 小组件。新的“li”元素基本上已在 AJAX 请求期间被动态追加到了“ul”元素中,这样做就成了!同时,还跨 AJAX 请求永久性地记住了这些小组件,因此可以更改它们的属性,并调用它们的事件处理程序。
此外,通过“Element”属性,还可以呈现任何 HTML 元素,并能借助下标运算符添加任何属性。
现在可以完全控制 HTML 标记,并能创建微型 AJAX 请求和响应,从而以认为适当的方式更新要在页面上更新的任何内容。只使用 4.8KB 的 JavaScript,就实现了这一切。已将 Web 应用程序 AJAX 开发变成与普通旧 Windows 窗体开发一样易于实现。在此过程中,Web 应用程序的运行速度和响应速度最终快了 100 倍。
练习使用 Hyperlambda
数月前,我在 2017 年 6 月刊《MSDN 杂志》中撰写了“使用 Hyperlambda 让 C# 更加动态化”(msdn.com/magazine/mt809119) 一文,探讨了植根于执行树的非传统 Hyperlambda 编程语言。
之所以提到它是因为,借助 Hyperlambda 基于树的方法,声明 AJAX 小组件层次结构变得极其简单。将 p5.ajax 和 Hyperlambda 相结合,从而使用 AJAX TreeView 小组件,一些显著的效果立刻显现。
我们来研究一下。首先,除了 Phosphorus Five 之外,还需要按照 bit.ly/2vbkNpg 中的说明操作,将 System42 下载到主 p5.webapp 文件夹中。然后,启动 System42(其中包含超快的 AJAX TreeView 小组件),打开“CMS”,单击“+”新建 lambda 页面,并粘贴图 5 中的代码。
图 5:创建支持遍历磁盘上文件夹的 AJAX TreeView
create-widget
parent:content
widgets
sys42.widgets.tree
crawl:true
items
root:/
.on-get-items
list-folders:x:/../*/_item-id?value for-each:x:/@list-folders/*?name list-folders:x:/@_dp?value split:x:/@_dp?value =:/ add:x:/../*/return/* src:@"{0}:{1}" :x:/@split/0/-?name :x:/@_dp?value if:x:/@list-folders/* not add:x:/../*/return/*/items/0/-
src class:tree-leaf return
items
单击“设置”,选择“空”作为“模板”,单击“确定”,保存页面并单击“查看页面”。
在检查 HTTP 请求通过网络传输的内容时,尝试展开 AJAX TreeView,便会意识到刚刚生成了一个可浏览文件夹的 AJAX TreeView,只使用了 24 行 Hyperlambda 来显示 p5.webapp 文件夹中的文件夹,而初始总带宽消耗仅为 10.9KB!
如果将这些结果与其他任何 AJAX 工具包进行比较,通常都会发现,除了通过网络传输的其他所有内容之外,其他工具包还需要下载许多兆字节的 JavaScript,而 Hyperlambda TreeView 包含的 JavaScript 则不超过 4.8KB。
生成此 AJAX TreeView,总共使用了 717 行纯 Hyperlambda 代码,并且仅使用了 Literal、Container 和 Void 小组件。大部分代码都包含注释,因此创建 AJAX TreeView 控件需要约 300 行代码。
使用小组件需要 24 行 Hyperlambda,以便可以浏览磁盘上的文件夹。不过,使用其他任何工具创建此控件将需要数千行代码,使用它也需要数百行代码,这在图 5 中只需要 24 行代码即可完成。
如果需要,现在可以转换 Hyperlambda 示例中的三行代码,最终生成自己专用的活动事件自定义小组件,这样通过一行代码就可以使用专用小组件了。有关具体操作说明,请访问 bit.ly/2t96gsQ。
因此,现在可以创建 AJAX TreeView,仅通过一行代码就能浏览服务器的文件夹。若要在其他工具包中创建等效项,通常需要涉及四种不同语言的数百行代码。而我们只通过涉及一种编程语言的一行代码,便实现了这一切,并且与竞争对手相比,性能速度最多可快 300 倍。
总结
想象一下,结果无论是在质量、速度、优化性、bug 数量方面,还是在效率方面,都比之前提升了 100 倍。若要确保使用的是最新产品,请从 bit.ly/2uwNv65 下载 Phosphorus Five,并从 bit.ly/2vbkNpg下载 System42。
Thomas Hansen 自 8 岁起便一直在开发软件,他于 1982 年就开始使用 Oric-1 计算机编写代码。他编写的代码偶尔确实是利大于弊。他热衷于 Web、AJAX、敏捷方法和软件体系结构。可通过 thomas@gaiasoul.com 与他取得联系。
衷心感谢以下 Microsoft 技术专家对本文的审阅:James McCaffrey
以上是关于速度的刺激:托管 AJAX 能否让 Web 应用程序提速?的主要内容,如果未能解决你的问题,请参考以下文章
支持 https 的 Owin 自托管控制台应用程序(无 Web api,无 SignalR)
如何让托管在 WebView2 控件中的 reactjs Web 应用程序使用 Windows 登录身份验证到 Okta?