各种AJAX方法的使用比较详解


阅读目录

开始

第一代技术:生成客户端代理脚本调用服务端

新技术的改进方向

第二代技术:jQuery直接调用WebService

第三代技术:更简单的数据格式

第四代技术:直接提交表单

多submit按钮的提交(用jQuery.form实现)

批量输入控件的提交(用jQuery.form实现)

提交复杂表单(用jQuery.form实现)

各种AJAX开发方法的对比与总结

相关链接

本文收集了在ASP.NET平台上,一些具体代表性的AJAX开发方法,我将用实际的示例代码来演示如何使用它们,让您感受AJAX的进化历程,同时也希望将一些优秀的AJAX开发方法介绍给您。

为了方便地介绍这些AJAX开发方法,我将它们划分为四代技术。

注意:按代划分AJAX技术纯属我个人的观点,只为了更好了区分它们。

此外,一些不借助任何框架类库的原始AJAX开发方法,本文将不讨论它们。

第一代技术:生成客户端代理脚本调用服务端

这类技术展示了第一代的AJAX框架的主要设计思想:在服务端为客户端生成代理脚本, 然后由这些代理脚本调用服务端,调用者可以不必知道整个调用过程是如何实现的, 而且在客户端的调用风格也基本与服务端的代码类似。

这类技术的代表作有:ASP.NET AJAX, AjaxPro 二个服务端框架。

下面我将用ASP.NET AJAX框架来演示如何进行AJAX开发。

首先,我们可以创建一个WebService服务:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
//若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
[System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService {

  [WebMethod]
  public int Add(int a, int b)
  {
    return a + b;
  }

这段代码就是一个普通的WebService代码,唯独需要注意的是:在类的定义上加了一个ScriptService修饰特性。

接下来,我们还需要在一个ASPX页面中,用ScriptManager为它生成客户端的代理脚本:

<asp:ScriptManager ID="ScriptManager1" runat="server">
  <Services>
    <asp:ServiceReference Path="/WebService1.asmx" InlineScript="true" />
  </Services>
</asp:ScriptManager>

说明:InlineScript="true"的设置并不是必须的,只是为了让我们看到ScriptManager到底生成了什么代码。

从截图可以看到,除了引入了二个必要的AJAX客户端类库外,还在客户端为WebService1生成了代理脚本。

有了这些代码后,我们可以用下面的JavaScript代码调用服务端:

function Call_Add(){
  WebService1.Add(1,2, ShowResult);
}
function ShowResult(result){
  document.getElementById("output").value = result;
}

前面这个示例太简单了,再来个参数复杂的示例吧,还是从先服务端开始,先定义一个参数类型:

public class Customer
{
  public string Name { get; set; }
  public int Age { get; set; }
  public string Address { get; set; }
  public string Tel { get; set; }
  public string Email { get; set; }
}

WebSerice的代码:

[WebMethod]
public string AddCustomer(Customer customer)
{
  if( customer == null )
    return "customer is null.";
  
  // 简单地返回一个XML字符串。
  // 告诉客户端:服务端收到了什么样的数据。
  return XmlHelper.XmlSerialize(customer, Encoding.UTF8);
}

仍然借用前面的ScriptManager设置,来看JavaScript的调用代码:

function Call_AddCustomer(){
  var customer = {Name: document.getElementById("txtName").value, 
          Age: document.getElementById("txtAge").value, 
          Address: document.getElementById("txtAddress").value, 
          Tel: document.getElementById("txtTel").value, 
          Email: document.getElementById("txtEmail").value};
  WebService1.AddCustomer(customer, ShowResult);
}

基本上还是与服务端的编码方式差不多,先创建一个customer对象,再传给调用方法。

在那个年代之前(2006年),原始的AJAX实现方式非常复杂,而这种方法让客户端代码风格看起来与服务端十分类似,这确实是个了不起的设计思路。 然而各种技术一直在改进中,现在,2013年,当我们再来回顾这种方法时,会发现它确实存在一些不完善的地方, 以至于现在使用这种方法的人很少了,这种技术被淘汰了!

其实我们可以从另一外角度来思考:如果这种方法真的很优秀,它就不可能被淘汰,正是因为有更优秀的方法出现了,它才会遭到淘汰的命运。

新技术的改进方向

前面介绍的那种AJAX方法能让客户端的调用代码与服务端的代码风格基本一致,看似很完美的方法为什么会被淘汰了呢?

我来分析一下这种开发方法的缺陷:

1. 前端代码不够独立,必须要在页面中添加引用之后才能调用服务端,这其实是一种强耦合。

2. 出现了更优秀的前端框架能简少获取调用参数的代码量。

继续阅读本文,您会发现后面我将要介绍的新方法都朝着解决这些缺陷在努力, 这些缺陷也算是指出了新技术的改进方向。

由于前端在调用服务端时,需要事先生成代理脚本,这种设计会阻碍前端代码的封装性。 您可以想象一下:如果客户端需要一个【获取当前用户信息】的功能,而这个功能必须由服务端实现的, 此时,我们就只能指望服务端为客户端生成代理类来调用这个功能了。 但这个功能太有用,许多地方都需要使用,您是不是会想将它提取到一个公用的文件中?

遗憾的是:就算您将这段调用代码提取到一个公共的public.js文件中,每个页面在引用public.js后, 并不能调用【获取当前用户信息】功能,因为代理脚本并不一定存在,public.js中的代码还不能运行起来。 怎么办?

答:为每个引用public.js的页面,再添加ScriptManager引用那个服务吧。

共用性越高的功能,您会发现这种引用代码的重复度也就越高。
简单说来,这种方法将WebService, aspx页面, js代码耦合在一起了。
由于耦合,您越用越发现越麻烦。

这种生成代理脚本的开发方法虽然能让前端代码与后端代码的风格一致,然而, 前端与后端毕竟不是同一种开发语言,它们要关注的方向也是不一样的。尤其是当更优秀的前端框架出现后, 这种后端包办前端的方法不仅让后端与前端耦合在一起,而且还限制了前端技术的发展, 最终只能是被抛弃的命运!

现在请记住我们为了提交一个Customer信息写了什么样的代码:

var customer = {Name: document.getElementById("txtName").value, 
        Age: document.getElementById("txtAge").value, 
        Address: document.getElementById("txtAddress").value, 
        Tel: document.getElementById("txtTel").value, 
        Email: document.getElementById("txtEmail").value};

我在介绍第四代技术时,您会发现它们消失了!

第二代技术:jQuery直接调用WebService

随意jQuery前端类库的流行,另一种新的开发方法也开始流行起来了。

HTTP调用本来是个很简单很透明的技术,只要指定一个URL,构造一个请求体就可以了, 前端代理脚本的方法将这个过程封装了起来,由于它的封装制造了耦合并限制前端的发展。 新的AJAX技术只能突破这个限制,舍弃这些代理脚本,直接调用后端代码。

下面的示例代码还是基于前面的示例,唯独不同的是:不是需要代理类,现在是直接调用服务端。

由于后端的服务代码没有改变,我也就不再贴出它们了,而且页面也不需要再添加什么引用,我们就直接看前端代码好了:

$.ajax({
  type:"POST", url: "/WebService1.asmx/Add", 
  contentType:"application/json",
  data:"{a: 1, b: 2}",
  dataType:'json',
  success:function(result){          
    $("#output").val(result.d);
  }
});

这段代码也能调用服务端的Add方法。

由于服务端采用JSON数据格式,所以需要在客户端多指定一些请求头,而这些事情以前是由代理脚本完成的。 虽然现在的代码稍微多一点,但是耦合没有了,更便于提取一些公用代码了。

事实上,如果您一直用这种方法调用WebService,那么jQuery提供了设置默认参数的功能, 我们可以利用这个特性减少代码量。

还是再来看一下前面那个复杂的参数类型的前端调用代码吧:

var customer = {Name: $("#txtName").val(), 
        Age: $("#txtAge").val(), 
        Address: $("#txtAddress").val(), 
        Tel: $("#txtTel").val(), 
        Email: $("#txtEmail").val()};
var jsonStirng = $.toJSON( {customer: customer} );
$.ajax({
  type:"POST", url: "/WebService1.asmx/AddCustomer", 
  contentType:"application/json",
  data: jsonStirng,
  dataType:'json',
  success:function(result){
    $("#output").val(result.d);
  }
});

主要的代码还是一样的,集中在获取调用参数,但是要转成JSON格式。

再次一次提醒:不要老是盯着要指定一大堆的jQuery参数,它们可以通过设置默认值的方式解决。
我之所以现在不想让它们消失,是因为后面还有更好的方法,先留着它们吧。

说明:这种方法不仅可以用于调用WebService,也可以调用WCF (basicHttpBinding),毕竟它们都使用HTTP协议。 不过,WCF还有一堆烦人的配置要设置,但这不是jQuery的问题,这是服务端框架的缺陷。

第三代技术:更简单的数据格式

前面我们看到了可以利用jQuery调用WebService,不过JSON的转换过程感觉有些多余,浏览器的提交就没有这个转换步骤嘛。 有时看到一些家伙们着还在JavaScript中拼接JSON字符串,我非常反感,所以这次的示例代码并没有给那种方法抹黑,我采用了一个JSON插件。

第三代技术就完美地解决了输入输出必须采用JSON问题,而且解决了POST的限制。

由于这次变革改变了数据格式,所以服务端也发生了改变, 新的框架解决了这些问题,例如:ASP.NET MVC框架,MyMVC框架都支持这个开发方式。

来看一下现在服务端的代码:

[Action]
public int Add(int a, int b)
{
  return a + b;
}
[Action]
public string AddCustomer(Customer customer)
{
  // 简单地返回一个XML字符串。
  // 告诉客户端:服务端收到了什么样的数据。
  return XmlHelper.XmlSerialize(customer, Encoding.UTF8);
}

注意:这种AJAX技术没有与客户端的任何耦合,只要知道一个URL就可以调用了。 来看客户端的代码吧:

$.ajax({
  type:"POST", url: "/AjaxDemo/Add.cspx", 
  data: {a: 1, b: 2},
  success:function(result){          
    $("#output").val(result);
  }
});
// 第二个调用
var customer = {Name: $("#txtName").val(), 
        Age: $("#txtAge").val(), 
        Address: $("#txtAddress").val(), 
        Tel: $("#txtTel").val(), 
        Email: $("#txtEmail").val()};
$.ajax({
  type:"POST", url: "/AjaxDemo/AddCustomer.cspx", 
  data: customer,
  success:function(result){
    $("#output").val(result);
  }
});

注意:type:"POST"并不是必须的,您也可以把它们改成GET方式提交。

如果您此时用Fiddler查看请求内容,会发现请求的数据采用的是key=value&key=vlaue的格式,与浏览器的方式一致。 由于没有JSON数据格式的限制,现在的参数项简单了。

现在再看上面这段代码,主要代码量在哪里?

是不是在获取调用参数那块?

继续阅读本文,我要让它消失。

第四代技术:直接提交表单

我们来看一下示例用的表单:

<form id="form1" action="/AjaxDemo/AddCustomer.cspx" method="post">
  <p><b>新增客户资料</b></p>
  <span>Name: </span><input type="text" name="Name" value="abc" /><br />
  <span>Age: </span><input type="text" name="Age" value="20" /><br />
  <span>Address: </span><input type="text" name="Address" value="武汉" /><br />
  <span>Tel:</span> <input type="text" name="Tel" value="12345678" /><br />
  <span>Email: </span><input type="text" name="Email" value="test@163.com" /><br />
  <br />
  <input type="submit" name="btnAddCustomer" value="保存客户资料" />
</form>

前面用了三种方法在提交这个表单,下面我们再来看一下更简单的提交方式:

<script type="text/javascript">
$(function(){
  // 只需要下面这个调用就可以将表单改成异步提交方式!
  $("#form1").ajaxForm({
    success:function(result){
      $("#output").val(result);
    }
  });
});
</script>

为了更清楚展示这种方法,我甚至把script标签也贴出来了。

如果您用过jQuery就应该能发现,真正的代码就只有ajaxForm的那个调用。

说明:ajaxForm是jQuery.form插件提供的功能。

服务端的代码继续使用前面示例的代码,所以就不贴出了。

再对比前面几种AJAX的实现方法,您说哪种方法最简单?

您对第四代AJAX技术有兴趣吗?

我还为它设计了三种不同场景下的示例,让您感受它的强大与简单,请继续阅读。

多submit按钮的提交(用jQuery.form实现)

您认为前面的示例太简单了,是吗?

可能有人会说,如果有多个submit按钮,这种方法就不合适了,我要响应每个按钮,为它们指定不同的URL !

真是这样吗? 看下面的示例吧。

相关的前端代码如下:

<form id="form1" action="/AjaxTestAutoAction/submit.cspx" method="post">
  <p><span>Input:</span>
    <input type="text" name="input" style="width: 300px" value="Fish Li" /></p>
  <p><span>Output:</span>
    <input type="text" id="output" style="width: 300px" readonly="readonly" /></p>
  <input type="submit" name="Base64" value="转换成Base64编码" />  
  <input type="submit" name="Md5" value="计算md5" />  
  <input type="submit" name="Sha1" value="计算sha1" />
</form>

<script type="text/javascript">
$(function(){  
  $("#form1").ajaxForm(function(result) {
    $("#output").val(result);
  });
});
</script>

服务端代码:

public class AjaxTestAutoAction
{
  [Action]
  public string Base64(string input)
  {
    return Convert.ToBase64String(Encoding.Default.GetBytes(input));
  }

  [Action]
  public string Md5(string input)
  {
    byte[] bb = Encoding.Default.GetBytes(input);
    byte[] md5 = (new MD5CryptoServiceProvider()).ComputeHash(bb);
    return BitConverter.ToString(md5).Replace("-", string.Empty);
  }

  [Action]
  public string Sha1(string input)
  {
    byte[] bb = Encoding.Default.GetBytes(input);
    byte[] sha1 = (new SHA1CryptoServiceProvider()).ComputeHash(bb);
    return BitConverter.ToString(sha1).Replace("-", string.Empty);
  }
}

代码仍然很清晰:

1. 服务端定义三个方法,对应三个submit按钮。

2. 前端还是只调用一个ajaxForm解决所有问题。

这种方法就是由前端的 jQuery, jQuery.form 以及服务端的MyMVC框架 共同实现的。 想像一下利用其它三种方法需要多少代码吧。

批量输入控件的提交(用jQuery.form实现)
再来展示另一个现实的例子,批量输入界面的提交。

页面表单代码如下:

JavaScript代码:

<script type="text/javascript">
$(function(){
  
  $("#form1").ajaxForm({
    success:function(result){
      $("#output").val(result);
    }
  });

});

服务端代码如下:

这个示例的全部代码就这么多,废话不想多说,您自己去想用其它方法需要多少代码!

提交复杂表单(用jQuery.form实现)
前面的示例都是直接提交表单,没有验证表单的过程,而且都以Textbox控件为主,再来个复杂的表单示例。

页面表单代码如下:

JavaScript代码:

<script type="text/javascript">
$(function(){
  
  $("#form1").ajaxForm({
    beforeSubmit: ValidateForm,
    success:function(result){
      $("#output").val(result);
    }
  });

  function ValidateForm(formData, jqForm, options) { 
    if( jqForm.context.ProductName.value.length == 0 ){
      alert("商品名称不能为空。");
      $(jqForm.context.ProductName).focus();
      return false;
    }
    return true;
  }
});

</script>

服务端代码:

[Action]
public string AddProduct(Product product)
{
  // 简单地返回一个XML字符串。
  // 告诉客户端:服务端收到了什么样的数据。
  return XmlHelper.XmlSerialize(product, Encoding.UTF8);
}

各种AJAX开发方法的对比与总结

看过了这些示例后,我们再来回顾这些AJAX方法的进化过程:

1. 以ASP.NET AJAX为代表的【生成客户端代理脚本调用服务端】技术, 为了包装原始AJAX的复杂过程,服务端为客户端生成了代理脚本, 这种封装后的客户端在调用方式上与服务端基本一致,看起来简化了不少,而且降低了开发门槛, 然而,它的优点也是它是它的最大缺点:服务端包办了客户端的事情,它完全没有想到客户端技术也在进步! 当更优秀的前端技术出现时,它的结局只能是淘汰。

2. 【jQuery直接调用WebService】可以看做是第一代技术的改进,它丢弃了服务端生成代理脚本的功能, 直接在客户端准备服务端所需要的数据格式,借助jQuery内部对XmlHttpRequest的封装,也能方便地调用服务端。 这种方法解决了客户端、服务、页面三方的耦合,但是数据格式却受到序列化方式的限制,使得起来怪怪的。 这种怪怪的感觉其实也是不方便的表现。

3. 为了让前端更方便地调用服务端,服务端框架只能改变,ASP.NET MVC框架和MyMVC框架都支持更简单的数据格式, 而且不需要那个多余的asmx文件,直接用类库就可以响应客户端请求。 这类技术的最主要特点是:用更简单的数据格式就可以调用服务端。 由于数据格式简单化,为以后的继续改进留下了机会。

4. 由于服务端不要求序列化的数据格式,且前端技术仍在进步,终于jQuery.form插件可以让我们不需要关注表单数据的收集过程, 它能模拟浏览器的提交行为,正确识别【成功控件】并将它们提交到服务端,因此代码得到最大限度的缩减,让AJAX开发过程更加容易。

前面几个采用jQuery.form的示例也让我们看到:不管表单是什么样的,永远只需要一个调用。

而且它将jQuery的调用过程也做了非常好的封装,所以我认为这是最容易使用的AJAX开发方法。



相关阅读:
win7升级win8系统后鼠标间歇性失灵如何解决
php微信支付之APP支付方法
win10预览版10061系统主题颜色怎么更改
Jquery实现仿腾讯微博发表广播
PHP 抽象方法与抽象类abstract关键字介绍及应用
使用配置类定义Codeigniter全局变量
WordPress主题制作之模板文件的引入方法
如何解决mysqlimport: Error: 13, Can't get stat of 的问题
快速解决owin返回json字符串多带了双引号"多了重string转义字符串
JavaWeb开发入门第一篇必备知识讲解
php使用strip_tags()去除html标签仍有空白的解决方法
HTML5之SVG 2D入门7—SVG元素的重用与引用
JavaScript中常见获取元素的方法汇总
简单掌握HTML中水平线标注与代码注释的用法
快速导航
PHP MySQL HTML CSS JavaScript MSSQL AJAX .NET JSP Linux Mac ASP 服务器 CMS SQL jQuery C# C++ java Android IOS oracle MongoDB PostgreSQL SQLite 交通频道 偃师汽车站货运部 河南省洛阳市偃师市
荆家客运站 山东省淄博市桓台县
汽车南站 东三环路
增城永和车站 永和新新公路15号
仁怀三合客运站 三合镇三合水泥厂东北200米附近
道县汽车总站 湖南省永州市道县
东王营客运站 河南省周口市西华县
高寺路客运站 河北省邢台市威县
广饶汽车总站 山东省东营市广饶县
乌鲁木齐客运段 站前街705号
田东思林汽车站 广西壮族自治区百色市田东县
麻城夫子河中心客运站 湖北省黄冈市麻城市
昭通市汽车客运站 云南省昭通市昭阳区
交泰乡汽车客运站 四川省绵阳市梓潼县
青岛汽车总站迎客厅 山东省青岛市四方区
朝阳市召都巴客运站 辽宁省朝阳市龙城区
昭平汽车总站餐饮部 广西壮族自治区贺州市昭平县
高平汽车站 长平东街
苍南汽车西站 灵溪镇建兴西路455号
临城汽车站 河北省邢台市临城县
东辽金洲客运站 吉林省辽源市东辽县
杨各庄汽车客运站 河北省唐山市迁安市
岩坦汽车站 岩坦街
忠信车站 广东省河源市连平县
万源龙潭汽车站 龙潭河风景区
渠县汽车站 营渠路534
福宁长途汽车站行旅托运、领认处 福建省宁德市霞浦县
溧阳上黄客运站 江苏省常州市溧阳市
平潭车站 万顺路
邢台中心汽车站诚诚快递中心 河北省邢台市桥东区
卫辉市城郊乡汽车客运站 河南省新乡市卫辉市
微山夏镇客运站 奎文路254
奉城汽车站 奉干公路
公吉客运站 一零二省道
沾化黄升客运站 山东省滨州市沾化县
象州石龙客运站 小红星幼儿园附近
南乐县韩张客运站 河南省濮阳市南乐县
吴江北厍汽车客运站 江苏省苏州市吴江市
赤水宝源汽车站 一碗水社区
磐石长崴子客运站 吉林省吉林市磐石市
水头镇短途客运站 浙江省温州市平阳县
浚县城关镇汽车客运站 河南省鹤壁市浚县
崖城车站 海南省三亚市
仙岛湖客运站 湖北省黄石市阳新县
顺义汽车站南彩站 北京市
大海林站 牡丹江市海林市
江安县四面山客运站 四川省宜宾市江安县
芝田镇客运站 河南省郑州市巩义市
南宁客运站湛江铁路招待所 南柳路离火车站150米
杨柑客运站 广东省湛江市遂溪县
海口市第二客运公司 滨海大道17号
南平峡阳客运站 福建省南平市延平区
袁口客运站 山东省济宁市梁山县
南岗汽车站 南岗区春申街26号
米东汽车站 新疆维吾尔自治区乌鲁木齐市米东区
乐亭汽车客运站 河北省唐山市乐亭县
大宁汽车站 广西壮族自治区贺州市八步区
草场乡晃桥农村客运站 四川省攀枝花市米易县
杨林桥车站 湖北省宜昌市秭归县
新余城南汽车站 江西省新余市渝水区
郓城县汽车站候车售票大厅 山东省菏泽市郓城县
罗城汽车总站 广西壮族自治区河池市罗城仫佬族自治县
雷高客运站 广东省湛江市雷州市
科尔沁左翼后旗金宝屯客运站 内蒙古自治区通辽市科尔沁左翼后旗
蒲城西路客运汽车站 陕西省渭南市蒲城县
大姚短途客运站 云南省楚雄彝族自治州大姚县
邓州张楼乡客运站 河南省南阳市邓州市
宁安东京城客运站 黑龙江省牡丹江市宁安市
随州环潭汽车客运站 湖北省随州市曾都区
恒风交运秦塘客运站 浙江省金华市义乌市
莘塔汽车客运站 江苏省苏州市吴江市
南宁金陵客运站 三二四国道
高桥汽车站 湖南省邵阳市新宁县
富锦兴隆岗站 兴隆岗镇
五华华益汽车运输公司 广东省梅州市五华县
安阳市汽车客运南站 河南省安阳市文峰区
莆田汽车站地下停车场 福建省莆田市荔城区
常宁市江河车站 湖南省衡阳市常宁市
萧县汽车站 安徽省宿州市萧县
南屏乡临时客运站 浙江省台州市天台县
富民款庄客运站 云南省昆明市富民县
老汽车站地块拆迁安置办公室 江苏省淮安市盱眙县
英都汽车站 福建省泉州市南安市
玉田汽车客运站狮子桥分站 河北省唐山市玉田县
武汉杨春湖客运换乘中心 武汉站东广场附近
射阳黄尖客运站 江苏省盐城市射阳县
鸡东永安客运站 黑龙江省鸡西市鸡东县
安宁新村交通车站 新村路
海珠客运站联网售票窗口 广州大道南
漳州市汽车站候车厅 新华北路25号
蒲塘客运站 广西壮族自治区玉林市兴业县
逊克客运站 黑龙江省黑河市逊克县
云县涌宝客运站 云南省临沧市云县
大单客运站 三八三省道
汽车站东街 山东省潍坊市青州市
平舆万金店客运站 河南省驻马店市平舆县
月桥车站 四川省眉山市仁寿县
李村客运站 河南省三门峡市陕县
沙河镇汽车客运站 广东省清远市清新县
城步汽车北站 湖南省邵阳市城步苗族自治县

Copyright © 2016 phpStudy |