冬Blog

醉心技术、醉心生活
posts - 88, comments - 674, trackbacks - 9, articles - 1
  博客园 :: 首页 :: 新随笔 ::  :: 订阅 订阅 :: 管理

彻底的Ajax

Posted on 2008-01-02 16:20 冬冬 阅读(3022) 评论(21)  编辑 收藏 所属分类: Web Develop

刚读完称之为Rails圣经的《Web敏捷开发之道》,很多感想。先说说关于Ajax。

Ajax的框架太多了!!纯Js的有extjs、jQuery、Prototype等;集成于开发框架的有Ajax.Net等;Rails直接集成了Prototype。这些框架的实现方式也各不相同,但是大体有这么三种实现方式:

  1. UpdatePanel式
  2. Rails式
  3. 彻底的Ajax

1,UpdatePanel式

UpdatePanel的工作方式是:将用户的请求(连同ViewState)以JavaScript的方式发送的服务器,获得该请求的是Ajax.Net的服务器组件(定义在Web.Config中)而不是目标页面;该组件解析请求,并会调用目标页面执行完整的页面周期(就跟直接访问该页面一个效果),获得该页面的输出,并且提出要更新的UpdatePanel的内容,将这一部分Html返回给客户端的Ajax.Net Client Library。客户端脚本就可以更新UpdatePanel了。该图示如下。

image
UpdatePanel的工作方式

从图上可以很容易看出来,服务器页面不仅完全执行了而且还引入了Ajax.Net服务器组件的调用开销,这也是UpdatePanel适用于任何控件的原因。同学们也可以使用Fiddler结合断点调试(在PageLoad方法入口加断点)自己动手了解一下这个过程。

2,Rails式

Rails借助Prototye实现Ajax。客户端通过类似下面Prototype的脚本发起请求。

<form action="/store/add_to_cart/3" method="post" onsubmit="new Ajax.Request('/store/add_to_cart/3', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">

传输的数据:

POST /store/add_to_cart/1 HTTP/1.1
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: zh-cn
x-prototype-version: 1.5.0
Referer: http://192.168.1.122:3000/store
x-requested-with: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.20706)
Host: 192.168.1.122:3000
Content-Length: 61
Proxy-Connection: Keep-Alive
Pragma: no-cache
Cookie: _depot_session_id=ff9a536b4f87552687a7910b6d3b48e5
commit=%E6%B7%BB%E5%8A%A0%E5%88%B0%E8%B4%AD%E7%89%A9%E8%BD%A6

服务器端的Rails调用Action得到结果,然后渲染模板,这里的模板通常是一个Rjs文件。返回的是要执行的脚本(当然也可是别的你想让他返回的东西),类似下面的:

try {
Element.update("cart", "<div class=\"cart-title\">\u8d2d\u7269\u8f66</div>\n\n<table>\n\n  <tr id=\"current_item\">\n\n  <td>1&times;</td>\n  <td>Pragmatic Project Automation\u4e2d\u6587</td>\n  <td class=\"item-price\">29.95\u5143</td>\n</tr>\n  \n  <tr class=\"total-line\">\n    <td colspan=\"2\">Total</td>\n    <td class=\"item-price\">29.95\u5143</td>\n  </tr>\n  \n</table>\n\n<form method=\"post\" action=\"/store/checkout\" class=\"button-to\"><div><input type=\"submit\" value=\" \u7ed3 \u8d26 \" /></div></form>\n<form method=\"post\" action=\"/store/empty_cart\" class=\"button-to\"><div><input onclick=\"return confirm('\u786e\u5b9a\u6e05\u7a7a\u8d2d\u7269\u8f66?');\" type=\"submit\" value=\"\u6e05\u7a7a\u8d2d\u7269\u8f66\" /></div></form>\n");
$("cart").visualEffect("blind_down");
$("current_item").visualEffect("highlight", {startcolor: "#88ff88", endcolor: "#114411"});
}
catch (e)
{ alert('..........'); throw e }

这种方式要好于UpdatePanel的方式,虽然对于客户端来说没有什么不同,但是服务器端不再是执行一个完整的生存周期,而仅仅调用一个方法,开销要少很多。

3,彻底的Ajax

以上两种方式都存在一个问题:服务器端不仅要负责数据的运算,还要负责数据的显示,即Html或Javascript脚本的生成。

理想的Ajax应该是数据和表现完全分离的,即:客户端浏览器使用JavaScript发起运算请求并给出运输参数;服务器端负责运算,并把结果以数据的方式返回给浏览器;浏览器接到请求结果后,在客户端执行显示逻辑。

例如,用户在客户端输入了用户名,服务器端负责验证该用户是否存在。

发起的请求如:

POST /Default.aspx/IsUserExist HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Referer: http://222.195.149.103:10007/
Content-Type: application/json; charset=utf-8
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.20706)
Host: 222.195.149.103:10007
Content-Length: 41
Proxy-Connection: Keep-Alive
Pragma: no-cache

{"userName":"200117","userRole":"Expert"}

所执行的方法应该类似:

[WebMethod]
public static bool IsUserExist(string userName, string userRole)
{
    UserRole userRoleValue = (UserRole)Enum.Parse(typeof(UserRole), userRole, true);

    switch (userRoleValue)
    {
        case UserRole.Administrator:
            return DatabaseGateWay.GetNewDatabase().Administrators.Exist(userName);
        case UserRole.Expert:
            return DatabaseGateWay.GetNewDatabase().Experts.Exist(userName);
        default:
            return false;
    }
}

返回的结果类似:

HTTP/1.1 200 OK
Date: Wed, 02 Jan 2008 08:01:30 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: application/json; charset=utf-8
Content-Length: 11

{"d":false}

在这一过程中,传递的完全的是数据,客户端交付给用户的是“{"userName":"200117","userRole":"Expert"}”;服务器端返回的仅仅是“{"d":false}”。

服务器完全不必了解客户端是如何显示“该用户不存在”这一结果,而客户端也完全不需要知道服务器完成“判断该用户是否存在”这一逻辑。

这样便实现了客户端与服务器端、表现层与逻辑层的完全解耦合,使得服务器端的运算逻辑(通常以WebServices的形式给出)可以被Web、WinForm、Mobile等不同的客户端所复用。

另一方面这种方式仅在服务器端调用需要的操作,不形成额外的开销。传输的数据也非常至少(这个时候连接的建立将花费更多时间),这也节约了带宽,加快了响应速度(Ajax的主旨)。

Ajax.Net中集成的WebServices调用和PageMethod调用都属于这种形式。

Feedback

#1楼    回复  引用  查看    

2008-01-02 18:01 by Clark Zheng      
没看太懂,期待高手出现

#2楼    回复  引用  查看    

2008-01-02 18:29 by JesseZhao      
分析的不错哦

#3楼    回复  引用  查看    

2008-01-02 18:47 by 笑疯^_^      
刚刚的

#4楼    回复  引用  查看    

2008-01-02 19:09 by Rivers Zhao      
很好。有道理。只是最近一种方法,估计不是很容易使用,这样开发人员需要花较多精力在基础代码上。

#5楼    回复  引用  查看    

2008-01-02 20:42 by Jeffrey Zhao      
1和2其实可以说是同一种

#6楼 [楼主]   回复  引用  查看    

2008-01-02 20:45 by 冬冬      
@Rivers Zhao
不得不说,Ajax确实提高了Web开发的门槛。

@Jeffrey Zhao
1和2在服务器端的执行方式不同。

#7楼    回复  引用  查看    

2008-01-02 21:06 by Cat Chen      
你所说的,其实就是面向内容、面向脚本、面向数据这三种方式,这个在Ajax in Action一书中Dave Crane已经总结过。哪种更好,是要看应用情景的,并不存在最优方案。

在Ajax in Action一书中,感觉Dave更倾向于面向数据,然而在Prototype and Scriptaculous in Action一书中,他又选择了使用面向内容的方式编写示例。

#8楼 [楼主]   回复  引用  查看    

2008-01-02 21:52 by 冬冬      
@Cat Chen
“哪种更好,是要看应用情景的,并不存在最优方案。”

这话我赞成:设计无优劣,无非取舍二字。

#9楼    回复  引用  查看    

2008-01-02 22:23 by Jeffrey Zhao      
@冬冬
2和3是独立于技术的,1是asp.net ajax特有的(哦,其实别的框架也可以有),而且其实我想说的是,1是2的特例,是2在asp.net ajax中实现的特例。

#10楼    回复  引用    

2008-01-02 22:55 by laputa [未注册用户]
asp.net ajax 为了更傻瓜化,更加牵强的融合到asp.net中,更好更快的上手,牺牲了应用程序的性能

#11楼    回复  引用  查看    

2008-01-02 23:37 by Jeff Yang      
在asp.net ajax中很多不相关的事件处理最好加上if(!Page.IsPostBack)这个判断,否则浪费很多资源且可能造成困惑。

#12楼    回复  引用  查看    

2008-01-03 08:12 by 布尔      
本质都是一样的

#13楼    回复  引用  查看    

2008-01-03 08:34 by 小名阿铁      
Rails的确很强大,本就是采用MVC,但如果不清楚框架源代码,不熟悉Ruby,根本不知道本质(它的某些方法就用到了一些"稀奇古怪"的Ruby特性,非一般人能看懂).但或许对某些应用开发人员来说,这并不重要.框架本来就是拿来用的.
它适合应用,而不是学习.也其实Rails圣经的作者就说了Rails是一种技能.
学点Ruby,应用Rails,来做点副业还是不错的.(它很适合单枪匹马的项目)
(跑题了哈,不好意思)

#14楼    回复  引用  查看    

2008-01-03 08:42 by 黑羽飘舞      
该组件解析请求,并会调用目标页面执行完整的页面周期(就跟直接访问该页面一个效果),获得该页面的输出,并且提出要更新的UpdatePanel的内容,将这一部分Html返回给客户端的Ajax.Net Client Library。

貌似,ajax.net返回的数据不仅仅是“这一部分Html”吧?返回的是全部html而只刷新部分内容。

#15楼    回复  引用  查看    

2008-01-03 09:41 by 巫云      
第三种其实就是发送xmlhttp请求,然后得到数据,再通过DOM组合到页面。

#16楼    回复  引用  查看    

2008-01-03 13:00 by 布尔      
最关键的是,不要认为他们是对立的就可以了,在合适的时候用合适的工具,因人而异,因时而异

#17楼    回复  引用  查看    

2008-01-03 13:18 by Clingingboy      
是的,要看运用,并非最优方案。纯数据的传递会增加复杂度

#18楼 [楼主]   回复  引用  查看    

2008-01-03 13:36 by 冬冬      
@黑羽飘舞
开始我也认为传输的是全部的Html,经过抓包分析,发现只传输了要更新的部分的Html。

#19楼    回复  引用  查看    

2008-01-03 17:36 by Leem      
第三种不就是asp.net中的回调吗?

#20楼    回复  引用    

2008-01-04 11:31 by 雨中漫步的太阳 [未注册用户]
有什么么解决ajax对于搜索引擎的隔阂啊 期待高手

#21楼    回复  引用    

2008-05-18 00:08 by 赵志强 [未注册用户]
文章写的不错,不过感觉你在写教科书.你对AJAX(正确来说是JAVASCRIPT)的理解还有待提高.
喜欢你的"关于我"介绍.
第20楼关注的是个问题,但不是我们所考虑的,而是网络蜘蛛来做的事情.不过建议不要把页面用JS做烂,那样不会说明你有能力.

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-01-07 10:11 编辑过
 
另存  打印