详解JavaScript中jQuery和Ajax以及JSONP的联合使用


Posted in Javascript onAugust 13, 2015

借助于 XMLHttpRequest,浏览器可以在整个页面不刷新的情况下与服务端进行交互,这就是所谓的 Ajax(Asynchronous JavaScript and XML)。Ajax 可以为用户提供更为丰富的用户体验。

Ajax 请求由 JavaScript 驱动,通过 JavaScript 代码向 URL 发送一个请求,待服务端有响应时会触发一个回调函数,可以在这里回调函数里面处理服务端返回的信息。由于整个发送请求和响应的过程是异步的,所以在此期间页面中其它 Javascript 代码仍然继续执行,不会中断。

jQuery 对 Ajax 当然也提供了很好的支持,而且还抽象了各种浏览器对于 Ajax 支持方面另人痛苦的差异。它不但提供了全功能的 $.ajax() 方法,还有诸如 $.get(),$.getScript(),$.getJSON(),$.post() 和 $().load() 等更为简便的方法。

尽管被命名为 Ajax,但是很多 Ajax 应用并没有使用 XML,特别是 jQuery 方面的 Ajax 应用,大多数都没有使用 XML;反而用得比较多的情况是:纯文本、HTML 以及 JSON(JavaScript Object Notation)。

一般情况下,由于同源策略(同协议,同域名,同端口)的限制,Ajax 并不能跨域执行请求,除非使用诸如 JSONP(JSON with Padding) 之类的方案,才能实现一些受限的跨域功能。
关于 Ajax 的一些重要概念

GET vs POST,这是两种最常用的向服务端发送请求的方法,正确理解这两种方法的区别对于 Ajax 开发非常重要。

GET 方法通常用于执行一些非破坏性的操作(就是说,只从服务端获取信息,不修改服务端上的信息)。例如,搜索查询服务一般会使用 GET 请求。另外,GET 请求还可能会被浏览器缓存,这可能会导致一些不可预知的问题。一般情况下 GET 请求只能通过查询字符串的方式向服务端发送数据。

POST 方法通常用于在服务端上执行一些破坏性的操作(就是说,会修改服务端上的数据)。例如,当你发表一篇博客的时候,用的应该就是 POST 请求。和 GET 请求不一样,POST 请求不存在缓存问题。POST 请求中,查询字符串作为 URL 的一部分也能向服务端提交数据,但不推荐这种方法,所有数据应该跟 URL 分开单独发送。

数据类型,jQuery 通常要求指明服务端返回的数据类型,某些情况写数据类型可能已经包含在方法名称中了,如 $.getJSON(),除此之外,它都会被作为一个可配置的对象的一部分,该对象最终会作为 $.ajax() 方法的参数。数据类型通常有以下几种:

  •     text :纯文本,用于传输简单的字符串。
  •     html :用于传输一段 HTML。
  •     script :向页面中添加脚本。
  •     json :传输已格式化的 JSON 对象,它可以包含字符串、数组或对象。
  •     jsonp :用于传输从其他域下返回的 JSON 数据。
  •     xml :用于传输自定义的 XML 格式数据。

异步执行,Ajax 中的 A 指的是异步(Asynchronous)。说到这里可能很多 jQuery 初学者一下子很难理解什么叫异步,因为默认情况下 Ajax 请求就是异步的,服务端返回的信息并非马上就能获取到。所有服务端返回的信息只能在一个回调函数中处理。例如以下这段代码,是错误的:

var response;
$.get('foo.php', function(r) { response = r; });
console.log(response); // undefined!

正确的做法应该是在回调函数中处理服务端返回的数据,回调函数在 Ajax 请求成功完成时才被执行,这个时候才能获取到来自服务端的数据:

$.get('foo.php', function(response) { console.log(response); });

同源策略及 JSONP,前面已经说过,一般情况下 Ajax 的请求会被限制在相同协议(http 或 https)、相同端口、相同域名下才能正确执行,但是 HTML 的 <script> 标签却无此限制,它可以载入任何域下的脚本,jQuery 正是利用了这一点才得以拥有跨域执行 Ajax 的能力。

所谓 JSONP,就是其它域的服务端返回给我们的是 JavaScript 代码,这段代码可以被加载到 HTML 中的 <script> 标签中,这段 JavaScript 代码中包含有从其它域下的服务端返回的 JSON 数据,并以回调函数的形式提供。这样一来 jQuery 就回避了同源策略的限制,曲线拥有了跨域执行 Ajax 的能力。

Ajax 调试工具,现在比较新的浏览器如 Chrome 和 Safari,甚至 IE 都内置了调试工具,Firefox 也有无比强大 FireBug 插件,借助于这些调试工具,可以非常详细的查看 Ajax 的执行过程。
和 Ajax 相关的一些方法

jQuery 提供了好多种简便的 Ajax 方法,但是它们的核心都是 $.ajax,所以必须正确理解 $.ajax。

jQuery 的 $.ajax 是创建 Ajax 请求中最直接也是最有效的方法,它的参数是一个 JavaScript 对象,我们可以在这个对象中对 Ajax 作非常详细的配置。另外,$.ajax 方法还可以分别定义 Ajax 请求成功和失败时的回调函数;而且它以一个可配置的对象作为参数的特性,使得我们可以在 Ajax 方法外配置这个对象,然后再传进来,这非常有助于实现代码复用。关于这个方法的详细文档:http://api.jquery.com/jQuery.ajax/

一个典型的示例如下:

$.ajax({
  // 要请求的 URL
  url : 'post.php',

  // 要发给服务端的数据
  // (将会转化为查询字符串,如:?id=123)
  data : { id : 123 },

  // 定义此 Ajax 请求是 POST 还是 GET
  type : 'GET',

  // 服务端返回的数据类型
  dataType : 'json',

  // Ajax 成功执行时的回调函数;
  // 回调函数的参数即为服务端返回的数据
  success : function(json) {
    $('<h1/>').text(json.title).appendTo('body');
    $('<div class="content"/>')
      .html(json.html).appendTo('body');
  },

  // 如果 Ajax 执行失败;
  // 将返回原始错误信息以及状态码
  // 传入这个回调函数中
  error : function(xhr, status) {
    alert('Sorry, there was a problem!');
  },

  // 这里是无论 Ajax 是否成功执行都会触发的回调函数
  complete : function(xhr, status) {
    alert('The request is complete!');
  }
});

    备注:

    关于 dataType :如果这里定义的 dataType 跟服务端返回的数据格式不一样,我们的代码就可能会执行失败,并且很难查出原因,因为 HTTP 返回的状态码并没有显示出错。所以在执行 Ajax 请求的时候,一定要确保服务端返回的数据格式跟事先定义定义的一致。通常情况下验证 HTTP 头信息中的 Content-type 是行之有效的办法,对于 JSON 而言,对应的 Content-type 应该是 application/json。

$.ajax 的一些自定义选项

$.ajax 方法的自定义选项非常多,这也是此方法功能强大的原因所在。若要查阅所有自定义选项,可参考官方文档:http://api.jquery.com/jQuery.ajax/,下面只列出一些常用的选项:

    async :默认值是 true,如果需要 Ajax 的执行方式为同步,可将其设为 false。请注意,如果把这个值设为 false 了,那么你的其它 JavaScript 代码将会被中断执行,直到此次 Ajax 请求完毕,接受到服务端返回的数据为止才会恢复。所以,请慎用此选项。
    cache :设定是否缓存服务端发回的数据。对于 “script” 和 “jsonp” 之外的其它格式的数据而言,默认值是 true。如果被设置为 false,向服务器发送请求的时候,URL 中会被加入一个查询字符串,字符串的值是当前的时间戳,以确保每次请求的 URL 都是不同的,当然也就不存在缓存问题了。JavaScript 中获取时间戳的方法为 new Date().getTime()。
    complete :Ajax 请求执行完成时触发的回调函数,无论此次执行成功与否,该回调函数都会被触发。该回调函数可以接受服务端返回的原始信息及状态码。
    context :定义回调函数执行时的作用域(回调函数 function(s) {alert(this)} 中的 this 指向谁?)。默认情况下,回调函数中的 this 指向传递给 $.ajax 方法的参数,也就是那个大对象。
    data :要发送给服务端的数据,其值可以是一个对象或者查询字符串,如 foo=bar&baz=bim。
    dataType :服务端返回数据的类型。如果不设置这个选项,jQuery 会根据服务端返回数据的 MIME 类型自行判断。
    error :当 Ajax 执行错误时将会触发的回调函数,该函数接受原始的请求信息及状态码。
    jsonp :执行 JSONP 请求时需要制定的回调函数名称,默认值是“callback”。
    success :Ajax 成功执行时将会触发的回调函数。在函数中可获取服务端返回的信息(如果 dataType 被设置成 JSON,返回的数据应该是一个 JavaScript 对象),当然也可获取服务端返回的原始数据信息及状态码。
    timeout :给 Ajax 请求设置一个超时是时间,单位是毫秒。
    type :指定请求的方式,GET 或者 POST,默认值是 GET。其它如 PUT 和 DELETE 方式也可以用,但并不是所有浏览器都支持。
    url :要请求的 URL。

其中 url 选项是所有选项中唯一的一个必选项,其它选项都是可选的。
一些简便方法

如果你不需要那么多可配置的选项,也不关心 Ajax 执行错误时候的相关处理,jQuery 同样提供了一些非常有用的简便方法,以更简洁的方式完成 Ajax 请求。其实这些简便写法只是封装了 $.ajax,并把某些选项预先设定好。

jQuery 提供的简便方法如下:

  •     $.get :对给定的 URL 执行 GET 请求。
  •     $.post :对给定的 URL 执行 POST 请求。
  •     $.getScript :向页面中添加脚本。
  •     $.getJSON :执行一个 GET 请求,服务端返回的信息应为 JSON。

以上每种简便方法中都可传递如下参数:

    url :所请求的 URL,必须提供。
    data :向服务端发送的数据,可选。可以是一个对象,亦或查询字符串,如 foo=bar&baz=bim。

  •         备注:此选项不适用于 $.getScript。

    一个回调函数 :此回调函数在请求成功执行后被触发。可选。该回调函数接受服务端返回的数据,也包括请求的状态码及原始对象。
    数据类型 :服务端返回数据的类型。可选。

  •         备注:此选项只适用于那些在其名称中没指定数据类型的方法。

下面是三个简便方法的示例:

// 获取纯文本或者 html
$.get('/users.php', { userId : 1234 }, function(resp) {
  console.log(resp);
});

// 向页面中添加脚本,然后执行脚本中定义的函数。
$.getScript('/static/js/myScript.js', function() {
  functionFromMyScript();
});

// 从服务端获取 JSON 格式的数据。
$.getJSON('/details.php', function(resp) {
  $.each(resp, function(k, v) {
    console.log(k + ' : ' + v);
  });
});

$.fn.load

$.fn.load 方法是 jQuery 所有 Ajax 方法中唯一在选择器结果集上调用的方法。$.fn.load 方法从给定的 URL 上获取信息,然后填充到选择器结果集包含的元素中。另外,在 URL 后面还可以附加一些选择器,jQuery 最终只会把跟选择器相匹配的内容填充到对应的 HTML 元素中。

下面是示例:

$('#newContent').load('/foo.html');

// 或
$('#newContent').load('/foo.html #myDiv h1:first', function(html) {
 alert('加载完毕!');
});

Ajax 和 表单

在跟表单打交道方面,jQuery 的 Ajax 更显神威。最为有用的两个方法就是 $.fn.serialize 和 $.fn.serializeArray,下面是它们的用法:

// 将表单中数据转化为查询字符串
$('#myForm').serialize();

$('#myForm').serializeArray();
// 将表单中数据转化为对象数组,如:
[
  { name : 'field1', value : 123 },
  { name : 'field2', value : 'hello world' }
]

使用 JSONP

JSON 的本质其实是一种跨站点脚本注入。现在有很多比较好的网站都提供了 JSONP 服务,允许我们用他们预先定义好的 API 获取他们的数据。下面是一个示例,来源于 http://www.giantflyingsaucer.com/blog/?p=2682

服务端代码:

<?php
  header("content-type: text/javascript");

  if(isset($_GET['name']) && isset($_GET['callback'])) {
    $obj->name = $_GET['name'];
    $obj->message = "Hello " . $obj->name;

    echo $_GET['callback']. '(' . json_encode($obj) . ');';
  }
?>

客户端代码:

$.ajax({
  url: 'http://otherDomail.com:8080/JSONP/jsonp-demo.php',
  data: {name: 'Super man'},
  dataType: 'jsonp',
  jsonp: 'callback',
  success: function( response ) {
    console.log( response.message );
  }
});

jQuery 把 JSONP 的实现细节隐藏在幕后,我们要做的就是告诉 jQuery 服务端定义好的函数名以及我们请求的数据类型是 JSONP,其它方面和普通的 Ajax 请求没什么区别。
Ajax 事件

很多时候我们都需要在 Ajax 请求开始或结束时做一些操作,例如显示或隐藏一个 loading… 图片。这些工作本可以在每个 Ajax 请求中各自实现,但是 jQuery 提供了更好的方法,你可以像绑定普通事件一样绑定 Ajax 事件。若要参阅全部事件列表,可访问 http://docs.jquery.com/Ajax_Events。下面是简单示例:

$('#loading_indicator')
  .ajaxStart(function() { $(this).show(); })
  .ajaxStop(function() { $(this).hide(); });

 

Javascript 相关文章推荐
起点页面传值js,有空研究学习下
Jan 25 Javascript
jquery js 获取时间差、时间格式具体代码
Jun 05 Javascript
JS判断字符串长度的5个方法(区分中文和英文)
Mar 18 Javascript
javascript中tostring()和valueof()的用法及两者的区别
Nov 16 Javascript
JS传递对象数组为参数给后端,后端获取的实例代码
Jun 28 Javascript
jQuery Chosen通用初始化
Mar 07 Javascript
Jquery EasyUI $.Parser
Jun 02 jQuery
又拍云 Node.js 实现文件上传、删除功能
Oct 28 Javascript
微信小程序如何访问公众号文章
Jul 08 Javascript
layui实现三级导航菜单
Jul 26 Javascript
vue绑定class的三种方法
Dec 24 Vue.js
js中实现继承的五种方法
Jan 25 Javascript
JavaScript的面向对象编程基础
Aug 13 #Javascript
JavaScript简单判断复选框是否选中及取出值的方法
Aug 13 #Javascript
JavaScript实现将文本框的值插入指定位置的方法
Aug 13 #Javascript
JavaScript的jQuery库中function的存在和参数问题
Aug 13 #Javascript
js实现仿Discuz文本框弹出层效果
Aug 13 #Javascript
深入学习JavaScript中的原型prototype
Aug 13 #Javascript
javascript获取本机操作系统类型的方法
Aug 13 #Javascript
You might like
php堆排序(heapsort)练习
2013/11/13 PHP
PHP反向代理类代码
2014/08/15 PHP
PHP设计模式之适配器模式定义与用法详解
2018/04/03 PHP
Yii框架页面渲染操作实例详解
2019/07/19 PHP
php框架CI(codeigniter)自动加载与自主创建对象操作实例分析
2020/06/06 PHP
解决使用attachEvent函数时,this指向被绑定的元素的问题的方法
2007/08/13 Javascript
js查找父节点的简单方法
2008/06/28 Javascript
jquery 仿QQ校友的DIV模拟窗口效果源码
2010/03/24 Javascript
jQuery1.4.2与老版本json格式兼容的解决方法
2011/02/12 Javascript
解析瀑布流布局:JS+绝对定位的实现
2013/05/08 Javascript
js简单抽奖代码
2015/01/16 Javascript
Bootstrap 布局组件(全)
2016/07/18 Javascript
简单实现jQuery级联菜单
2017/01/09 Javascript
JS基于正则实现数字千分位用逗号分隔的方法
2017/06/16 Javascript
js实现扫雷小程序的示例代码
2017/09/27 Javascript
jQuery实现模糊搜索功能的方法分析
2018/06/29 jQuery
使用vue脚手架(vue-cli)搭建一个项目详解
2019/05/09 Javascript
es6函数之严格模式用法实例分析
2020/03/17 Javascript
用Python从零实现贝叶斯分类器的机器学习的教程
2015/03/31 Python
Django Admin中增加导出Excel功能过程解析
2019/09/04 Python
基于Python检测动态物体颜色过程解析
2019/12/04 Python
Python使用PyQt5/PySide2编写一个极简的音乐播放器功能
2020/02/07 Python
python中sort sorted reverse reversed函数的区别说明
2020/05/11 Python
CSS3系列之3D制作方法案例
2017/08/14 HTML / CSS
沪江旗下的海量优质课程平台:沪江网校
2017/11/07 全球购物
提高EJB性能都有哪些技巧
2012/03/25 面试题
车间组长岗位职责
2013/12/20 职场文书
公司同意接收函
2014/01/13 职场文书
二年级语文教学反思
2014/02/02 职场文书
建筑管理专业求职信
2014/07/28 职场文书
先进工作者事迹材料
2014/12/23 职场文书
2015年秋季灭鼠工作总结
2015/07/27 职场文书
2016大学生毕业实习心得体会
2016/01/23 职场文书
《岳阳楼记》原文、译文赏析
2019/09/10 职场文书
读《皮囊》有感:理解是对他人的最大的善举
2019/11/14 职场文书
vue backtop组件的实现完整代码
2021/04/07 Vue.js