Ajax的几个原则 与传统的Web应用程序所采用的开发模式相比,Ajax对Web开发人员而言意味着一种模式转变。Ajax立足于一些新的原则和规则:
ASP.NET的“部分呈现”技术 在ASP.NET中,“部分呈现”是一种在处于ASP.NET WebForm体系结构中仍可实现某些Ajax功能的途径。ASP.NET“部分呈现”是一种非常“智能”的技术,属于传统的WebForm回发模型。简单说来,使用“部分呈现”的页面,其回发体系结构和页面生命周期与非Ajax的ASP.NET页面。普通的ASP.NET页面回传机制如下图所示: “部分呈现”与普通的ASP.NET页面不同之处在只在于客户端的侦听器阻止浏览器的默认操作(表单提交),并用XMLHttpRequest装载的HTTP请求来替代HTTPRequest。这种方式不但可以节省用户的整页刷新时间,同时还可以节省开发人员在学习Ajax新的开发体系中所投入的时间(微软总是过于照顾开发者,以达到控制最终PC用户的目的)。ASP.NET使用“部分呈现”的Ajax页面回传机制如下图所示:
毋庸讳言,“部分呈现”在用户界面上提供了更好的体验(至少不用整页刷新了),所以非常适合页面内部回发,例如,对网格进行分页、变更选择后调整用户界面或就地编辑记录。但是,如果的应用程序是围绕很多独立的页面设计的,那么从一个页面到下一个页面的跳转仍需要整页加载。 由于“部分呈现”只是一种更“智能”页面回发,因此它具有与WebForm相同结构限制。例如,每个浏览器窗口只能有一个待决请求。对于当前的Web应用程序(提交表单、获取新页面)模型而言,此限制不会产生太大问题,但是,随着我们对Ajax认识的拓展和应用的深入,自然而然会期望用户可以同时执行多个活动。仅依靠部分呈现,用户是无法同时执行两个异步操作并将其完成的。“部分呈现”只能每次执行一个请求操作以保持“视图状态”的一致性(一致性仍是模型不可或缺的组成部分)。这一点严重违背了Ajax原则的第一个要求:异步。使用部分呈现,可以实现JavaScript驱动的回发,但每次只能有一个。如果在前一个操作完成之前触发了第二个操作,则待处理操作将被中止,以便新操作可以继续执行。可通过编程方式将这一后进得胜策略改为先进得胜模型,从而使当前操作仍保持活动状态,而新操作将被系统取消——实质上这仍然是每次只能执行一个操作。
单页界面模型(SPI) 为了充分利用Ajax,必须在单一页面中包含其中的全部功能,或者至少包含大部分功能。这称作单页界面 (SPI) 模型。在SPI模型中,浏览器与Web应用程序的所有交互只能在一个页面的范围内进行。此方法对Web来说是一种创新,但对于Windows桌面应用程序的开发却并不陌生。SPI模型就像是具有主(并且唯一)窗口的Windows应用程序(SDI)一样。 在SPI模型中,主页面是可以独立加载、更新和替换的一些可视元素的组合,如下图:
通过这种方式,可以不必在每次用户操作后重新加载整个页面。在任何时候,都只显示与应用程序当前阶段相关的可视元素和内容。其他所有内容均被隐藏;但只要应用程序流程中需要用到它,它就会显示出来。 SPI模型自然会启用许多交互性很强的功能,其中包括就地编辑、上下文相关的用户界面、即时用户反馈提示以及异步操作等。但SPI模型并不仅仅具有出色的性能或响应能力,它的主要优势在于针对用户体验方面做的重大改进。 不过,即使SPI拥有如此多的优点,我们还是应该清楚,使用SPI模型设计新应用程序是一项具有挑战性的工作,因为没有任何现成的模式和最佳实践。 为了构建纯Ajax应用程序,我们需要一个良好的用户界面小组件库来提供各种效果和特殊行为。我们需要一个内容丰富而又可以自定义的文档对象模型 (DOM),此模型使用标准的W3C DOM作为其基础引擎,允许我们定义自己的应用程序模型。最后,我们还需要一个服务器和客户端框架,以便轻松有效地开发用户界面和源代码脚本。最好还准备一些用于调试和测试所有这一切的工具。 在 SPI 模型中,主页面指向同一应用程序中的HTTP端点。它执行远程代码,但不会重新加载整个页面。而且,它还会使用生成HTML和脚本的控件来更新用户界面。这些控件非常智能,可以生成它们需要的许多JavaScript代码。很明显,只需要一些Javascript就可以轻松实现这种显示/隐藏技巧。
单页界面模型的缺点 虽然SPI模型带来了交互性更强的用户体验,但同时也引发了诸多问题,例如可搜索性、历史管理、可访问性和脱机支持等。多年以来,一直使用永久链接来跟踪Web页面。搜索引擎只需将一组关键字映射到一个或多个URL即可构建其业务。此模型的工作前提是假设Web应用程序中每个状态都对应一个页面和一个不同的URL。 如果SPI模型处在Ajax中,则此假设不再有效。如果所有一切(或大部分)都发生在同一页面中,则没有URL转换来标记不同的状态和不同的站点内容。因此,没有将内容(和关键字)与唯一URL相关联的简单方法。SPI模型的这一特性会影响可搜索性以及历史管理(例如,使用“后退”和“前进”按钮的能力)。浏览器历史记录最终可能会变为过时的概念,它们是传统静态Web模型的搭档。但是我们必须要知道,用户对这些按钮实在是太熟悉了,简单地禁用它们并不是一个可行的办法。 可访问性是Ajax应用程序的另一个大问题。大多数流行的屏幕读取器在处理通过DOM脚本生成的任何内容时都面临很大的困难。按照设计,所有形式的Ajax(包括部分呈现)都严重依赖于DOM脚本。因此,我们需要通过其他途径来解决可访问性问题。我们需要使用<noscript>标记静态信息。
可访问的富Internet应用程序(ARIA) W3C正在制定被称为“可访问富 Internet 应用程序”(ARIA) 的新标准,它主要由HTML标记的读取器扩展组成。一些比较流行的客户端Ajax库已经开始支持某些ARIA功能了(目前RIA领域两大巨头:Adobe的Flex、微软的SilverLight)。 对于脱机应用程序是怎样的情况?许多开发人员认为脱机Ajax应用程序不可能实现,因为Ajax应用程序仍然完全基于Internet。在我看来,这种说法虽然并非完全错误,但也有点过于简单化了。现在,几乎所有Web应用程序(AJAX 和非 AJAX)都基于 Internet 或 intranet。但是,非Ajax应用程序的确可以脱机工作。例如,对于历史记录管理,启用脱机导航的魔力完全在于浏览器。在传统的Web应用程序中,每个HTTP请求都由浏览器来管理。如果没有可用连接(在引发HTTP 404错误之前),浏览器会在其本地页面缓存中进行查找。 Ajax应用程序不同于传统的Web应用程序,它使用XMLHttpRequest对象而非浏览器引擎来发送HTTP请求。对于支持脱机的Ajax应用程序,您只需为XMLHttpRequest对象赋予访问浏览器缓存的权限或赋予创建并管理其自身已访问页面的缓存的能力即可。某些Ajax框架已开始引入此功能。但这并非是一件容易的事,因为它涉及从JavaScript代码访问磁盘(而Javascript这一功能在设计之初就被阉割了,智能调用浏览器对应的COM对象来访问本地文件)。
AJAX模式概述 在Google等等公司的努力和倡导下,下一代基于Web的应用程序将直接面向Ajax,而且会更多直接面向富Internet应用程序 (RIA)。起初,引领这一革新版本的是以下三大类应用程序:基于 HTML 的传统站点、为了将多个系统集成到一个基于 Web 的前端而构建的混合应用程序、胖客户端。 对于基于 HTML 的传统站点,部分用户界面加载(部分呈现)是实现 AJAX 的一种简便方法,它对现有代码和技能的影响非常小。 而混合程序的概念本身未必适合于Ajax和改进的用户交互。它只是一种从各种来源收集数据并将其一并放入一个统一而又一致的用户界面中的方法。此操作也可以在传统的服务器对服务器的情况下执行。但是坦率地说,Ajax可以使其更加简单有效。 使用Ajax构建胖客户端是一个最严峻的挑战。胖客户端可以是分布式企业系统的前端,也可以是业务线应用程序的表现逻辑层。它还可以是IT部门决定作为Web应用程序而公开的独立应用程序。这些应用程序无论是发布到Internet上还是限制在intranet内,都需要常规桌面UI所具有的丰富性和速度。 与Windows开发相比,在交互性和响应性方面Web开发都是一种倒退。利用Ajax,开发人员可以使用其中的工具向本质上不同的模型演化。但其中存在着不容忽视的折衷。一方面,有数百万的用户和开发人员已习惯了使用旧的Web及其历史模式、脱机导航、收藏夹、单一操作、页面转换和永久链接等。另一方面,开发人员采用的却是Ajax及其并行操作模式。在这种情况下,对于用户任务,Ajax模型需要真正的恢复模型,而不仅仅是使用浏览器的历史记录和页面导航功能。 要对SPI模型编写代码,需要使用一组新的设计模式。下表列出了一些最流行的Ajax模式。其中大部分都侧重于用户界面技术和排列:
唯一 URL 模式 URL是Web的基础。用户可以将中意的URL保存下来以供将来参考、可以按照URL所指开始新的内容体验,此外还可以使用URL回到先前的状态。在Ajax和SPI模型中,应用程序可以在单个URL中完成许多任务。这将使Web体验的核心支柱面临彻底的改变,即:应用程序的离散状态是由不同的URL来标识的。 浏览器会在用户浏览时构建其各自的URL缓存。但如果使用Ajax,许多操作都不通过浏览器,因此不会被缓存到访问过的URL列表中(在此列表中可驱动“后退”和“前进”菜单)。另一方面,客户端浏览器不会提供将URL添加到列表中的Javascript代码编程模型。在现有列表中,浏览器对象模型只会提供向前和向后的导航方法。 “唯一URL”模式为每个重要的应用程序状态都分配一个唯一的、含义鲜明的URL。例如,如果用户在Ajax页面中通过单击来编辑某个值,则新URL会被添加到浏览器缓存中,即使此操作是通过XMLHttpRequest在同一页面中执行的。 可使用以下 Javascript 来更改URL而无需重新加载页面: window.location.hash = stateInfo; 此代码的作用是将以#作为前缀的片段添加到URL中,如下所示: http://www.contoso.com/shopping.aspx#edit-1234 使用此模式时,URL实际上是在启动任何给定的Ajax操作时发生改变的,因此可以通过浏览器来跟踪应用程序状态的变化。 但是,要执行的操作远不止捕获URL这样简单。如果浏览器被定向到基于哈希值的URL,它首先会加载主URL,然后再查找具有此哈希名称的页面段。在Ajax上下文中,哈希名称并不指向实际的页面段,而是指向代表当前状态的特定于应用程序的信息。例如,edit-1234 可能表示正在编辑的项目其ID是1234。实际格式完全取决于开发者。 如果浏览器找不到适当的段,则它将忽略URL哈希值。这样,用户会加载该页面,但可能不是以预期的应用程序状态。此外还需要另一个技巧。开发者应截取页面的onload事件、分析URL、提取哈希值并运行将页面置于期望状态所需的 JavaScript 代码,如下所示: window.onload = function() {
checkAndParseURL(); } checkAndParseURL() { var state = window.location.hash;
restorePage(state); }
在ASP.NET 3.5扩展所提供的历史记录支持中也采用了类似的方法。ASP.NET 3.5扩展中将以添加到ScriptManager控件的新属性和事件的形式显示出来。但最终,它将是“唯一 URL”模式的具体实现。 另外还应注意,基于URL哈希值的技巧对IE无效,因为IE无法识别出URL哈希值的变化,除非是内嵌帧。实际上,所有浏览器在处理段导航方面所表现出的行为特点都是互不相同的。
超时模式 Ajax的其中一个最大优点是可以实现实时页面更新。但是,实时更新如果被误用,可能会成为应用程序的严重威胁。假设某个用户显示了一个活动页面,此页面每隔几秒钟轮询一次服务器以更新一些内容。如果该用户离开几个小时,但没有关闭浏览器。这样做产生的结果是,页面不断发送请求,给服务器带来大量(而且无用)的工作负荷。 如何能够确定客户端会话是否超时?在服务器上存在着会话超时,而在Ajax中也存在着不容忽视的客户端会话。要检测客户端会话的结束,需要检查在给定时间段内是否有用户活动(例如单击和敲击)。监视键盘和鼠标活动的任务可能会非常繁重;我们通常都采取一种基于定时器的方法,这种方法不但简单而且很有效。 要根据定时器检测会话的结束,应将客户端定时器设置为经过指定秒数(实际当中更有可能是分钟数)之后过期、停止正在执行的任务并弹出一个警告框。如果用户对提示做出响应,则会照例重新开始处理。 下面代码描述了超时模式的本质。在页面中嵌入了一个时钟。此时钟可使用 UpdatePanel 中的 Label 控件来获取,并由 Timer 控件定期更新,如下所示: <script type="text/javascript">
var timer = null; function pageLoad()
{ if (timer === null) { timer = new Samples.TaskTimer(5000, stopTask);
timer.start(); } } function pageUnload()
{ if (timer != null) timer.stop(); } function stopTask()
{ // Stop the clock
var clock = $find("<%= Timer1.ClientID%>"); clock._stopTimer(); AskIfTheUserWantsToContinue(); } function AskIfTheUserWantsToContinue()
{ // Ask if the user wants to continue
var answer = window.confirm(
"Is it OK to continue with the clock?");
if (answer)
{ // Restart the task
var clock = $find("<%= Timer1.ClientID%>"); clock._startTimer(); // Restart our own timeout engine
if (timer !== null) timer.start(); return;
} } </script> protected void Timer1_Tick(object sender, EventArgs e) { Label1.Text = DateTime.Now.ToLongTimeString(); } 此时钟代表一项繁重的任务,可能会造成服务器请求溢出。其思路是设置一个定时器,定期询问用户是否确实想要继续运行时钟。超时代码首先会停止时钟,然后显示消息框。得到用户响应后,时钟重新启动。 此代码利用 $find 函数来定位 ASP.NET AJAX 组件,在本例中,它还是 ASP.NET 定时器服务器控件的客户端对象模型。 |
关于Ajax模式与Web单页模式(SPI)的几点思考
最新推荐文章于 2021-08-05 15:37:18 发布