详解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 相关文章推荐
JavaScript 学习笔记 Black.Caffeine 09.11.28
Nov 30 Javascript
juqery 学习之四 筛选查找
Nov 30 Javascript
关于extjs treepanel复选框选中父节点与子节点的问题
Apr 02 Javascript
jQuery使用after()方法在元素后面添加多项内容的方法
Mar 26 Javascript
js拖拽的原型声明和用法总结
Apr 04 Javascript
完美解决linux下node.js全局模块找不到的情况
May 16 Javascript
JavaScript反射与依赖注入实例详解
May 29 Javascript
vue中axios请求的封装实例代码
Mar 23 Javascript
在vue中获取微信支付code及code被占用问题的解决方法
Apr 16 Javascript
关于element-ui的隐藏组件el-scrollbar的使用
May 29 Javascript
Vue3.0 响应式系统源码逐行分析讲解
Oct 14 Javascript
JavaScript 实现HTML DOM增删改查操作的常见方法详解
Jan 04 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
2021年最新CPU天梯图
2021/03/04 数码科技
分享一下贝贝成长进度的php代码
2012/09/14 PHP
php如何解决无法上传大于8M的文件问题
2014/03/10 PHP
PHP读取XML格式文件的方法总结
2017/02/27 PHP
使用PHPStorm+XDebug搭建单步调试环境
2017/11/19 PHP
PHP等比例压缩图片的实例代码
2018/07/26 PHP
《JavaScript高级程序设计》阅读笔记(三) ECMAScript中的引用类型
2012/02/27 Javascript
jQuery Ajax异步处理Json数据详解
2013/11/05 Javascript
JavaScript控制图片加载完成后调用回调函数的方法
2015/03/20 Javascript
jQuery 遍历函数详解
2015/07/05 Javascript
javascript中类的定义方式详解(四种方式)
2015/12/22 Javascript
javascript获取图片的top N主色值方法详解
2018/01/26 Javascript
vue.js内置组件之keep-alive组件使用
2018/07/10 Javascript
vue中,在本地缓存中读写数据的方法
2018/09/21 Javascript
JavaScript数组去重实现方法小结
2020/01/17 Javascript
理解Python中的With语句
2015/02/02 Python
深入理解Python中装饰器的用法
2016/06/28 Python
Python中列表和元组的使用方法和区别详解
2020/12/30 Python
使用Python脚本和ADB命令实现卸载App
2017/02/10 Python
关于Django显示时间你应该知道的一些问题
2017/12/25 Python
Python线性回归实战分析
2018/02/01 Python
Python中的Numpy矩阵操作
2018/08/12 Python
实例讲解python中的序列化知识点
2018/10/08 Python
详解python with 上下文管理器
2020/09/02 Python
Python之Sklearn使用入门教程
2021/02/19 Python
日本最大级玩偶手办购物:あみあみ Amiami
2018/04/23 全球购物
First Aid Beauty官网:FAB急救面霜
2018/05/24 全球购物
行政管理人员精品工作推荐信
2013/11/04 职场文书
小学教师事迹材料
2014/01/13 职场文书
2014新年元旦活动策划方案
2014/02/18 职场文书
技术总监管理岗位职责
2014/03/09 职场文书
乡镇纠风工作实施方案
2014/03/22 职场文书
毕业生爱心捐书倡议书
2015/04/27 职场文书
趣味运动会广播稿
2015/08/19 职场文书
《小摄影师》教学反思
2016/02/18 职场文书
sql时间段切分实现每隔x分钟出一份高速门架车流量
2022/02/28 SQL Server