jQuery源码分析系列(37) : Ajax 总结
综合前面的分析,我们总结如下3大块:
- jQuery1.5以后,AJAX模块提供了三个新的方法用于管理、扩展AJAX请求
- 为了整体性与扩展性考虑,把整个结构通过Deferred实现异步链式模型,Promise对象可以轻易的绑定成功、失败、进行中三种状态的回调函数,然后通过在状态码在来回调不同的函数就行了
- 出于同源策略考虑,存在跨域问题,所以ajax内部的处理总的来分2大块
- 基于XMLHttpRequest的ajax请求
- 基于script的jsonp跨域请求
引入Deferred统一回调体系
jQuery的链式方法是大是通过返回this的引用,但是ajax的链式不是那么简单的,因为ajax可以异步操作,所以返回的是一个异步模型对象Promise
当然如果只是deferred = jQuery.Deferred() 返回这个对象也是没意义的,因为无法关联到实际的数据
所以jquery内部构建了一个增强版的jqXHR对象,除了混入Promise模型,还增强了一些方法与接口
jqXHR 扩充基本的方法与接口
jqXHR = {// 准备状态readyState: 0,// Builds headers hashtable if needed// 如果需要,创建一个响应头参数的表getResponseHeader: function(key) {var match;// 如果状态为2,状态2表示ajax完成if (state === 2) {// 如果没有相应头if (!responseHeaders) {// 相应头设空responseHeaders = {};// 组装相应头while ((match = rheaders.exec(responseHeadersString))) {responseHeaders[match[1].toLowerCase()] = match[2];}}// 响应头对应的key的值match = responseHeaders[key.toLowerCase()];}return match == null ? null : match;},// Raw string// 返回响应头字符串getAllResponseHeaders: function() {// 看看是否接收到了,接收到直接返回,否则为nullreturn state === 2 ? responseHeadersString : null;},// Caches the header// 设置请求头setRequestHeader: function(name, value) {var lname = name.toLowerCase();if (!state) {// 如果requestHeadersNames[ lname ]不为空,// 则requestHeadersNames[ lname ]不变,name设置为该值// 否则,requestHeadersNames[ lname ]不空,// 则requestHeadersNames[ lname ]设置为name,// 该映射关系用于避免用户大小写书写错误之类的问题,容错处理name = requestHeadersNames[lname] = requestHeadersNames[lname] || name;//现在的name是对的,或者是第一次设置这个name,不需要容错//设置请求头对应值requestHeaders[name] = value;}return this;},// Overrides response content-type header// 重写相应头content-typeoverrideMimeType: function(type) {if (!state) {s.mimeType = type;}return this;},// Status-dependent callbacks// 对应状态的回调函数集statusCode: function(map) {var code;if (map) {//如果状态小于2,表示旧的回调可能还没有用到if (state < 2) {for (code in map) {// Lazy-add the new callback in a way that preserves old ones// 用类似链表的方式添加,以保证旧的回调依然存在statusCode[code] = [statusCode[code], map[code]];}} else {// Execute the appropriate callbacks// 无论Deferred成功还是失败都执行当前状态回调 jqXHR.always(map[jqXHR.status]);}}return this},// Cancel the requestabort: function(statusText) {var finalText = statusText || strAbort;if (transport) {transport.abort(finalText);}done(0, finalText);return this;} };
看看我们ajax的写法
$.ajax({url: "php.html",context: document.body,complete: function() {console.log(this)} }).done(function() {console.log(this) });
链式了一个done方法,done是Promise模型中的成功回调,因为ajax返回的是jqXHR对象
所以jqXHR就需要混入Promise模型
deferred.promise(jqXHR).complete = completeDeferred.add;jqXHR.success = jqXHR.done;jqXHR.error = jqXHR.fail;
看ajax源码前需要了解回到队列与Deferreds
jqXHR混入了Promise模型处理,当然只能读防止修改,之外还增加了一个complete的的回调队列
具体怎么使用,看后面
for (i in {success : 1,error : 1,complete : 1 }) {jqXHR[i](s[i]); }
很巧妙的一个处理,把用户配置文件中的回调函数给注册到这个jqXHR的回调体系中
所以就把所有的有关回调都绑定到了jqXHR对象上了
ajax提供3种事件通知接口
1 提供全局事件,外部的视图可以根据ajax状态进行改变
2 提供内部事件接口,根据流程做相对应的处理
3 提供链式事件接口,通过Promise实现
当ajax开始时模拟全局事件,ajaxStart
这里主要利用了jQuery.event.trigger和jQuery.fn.trigger模拟发事件
if (fireGlobals && jQuery.active++ === 0) {// 则通过jQuery.event.trigger模拟触发jQuery.event.trigger("ajaxStart"); }
ajax发送消息,触发ajaxSend
/*** 全局事件ajaxSend* 如果需要,对特定对象触发全局事件ajaxSend*/ if (fireGlobals) {globalEventContext.trigger("ajaxSend", [jqXHR, s]); }
结束时触发ajaxSuccess或ajaxError,再出发ajaxComplete,如果全部ajax结束则触发ajaxStop。
if (fireGlobals) {globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]);}// Complete completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);if (fireGlobals) {globalEventContext.trigger("ajaxComplete", [jqXHR, s]);// Handle the global AJAX counterif (!(--jQuery.active)) {jQuery.event.trigger("ajaxStop");}}
关于缓存数据
如果我们的请求为GET的时候的处理,用户通过data自定义了一些数据,那么这些数据只能通过拼接成url传递给服务端
我们需要通过给地址附加参数_=xxx来避免缓存
if (s.cache === false) {s.url = rts.test(cacheURL) ?// If there is already a '_' parameter, set its valuecacheURL.replace(rts, "$1_=" + ajax_nonce++) :// Otherwise add one to the endcacheURL + (ajax_rquery.test(cacheURL) ? "&" : "?") + "_=" + ajax_nonce++; }
从jQuery 1.5开始,$.ajax()
返回XMLHttpRequest(jqXHR)对象,该对象是浏览器的原生的XMLHttpRequest对象的一个超集。
例如,它包含responseText
和responseXML
属性,以及一个getResponseHeader()
方法。
当传输机制不是是XMLHttpRequest时(例如,一个JSONP请求脚本,返回一个脚本 tag 时),jqXHR对象尽可能的模拟原生的XHR功能。
从jQuery 1.5.1开始, jqXHR
对象还包含了overrideMimeType
方法 (它在jQuery 1.4.x中是有效的,但是在jQuery 1.5中暂时的被移除)。
.overrideMimeType()
方法可能用在beforeSend()
的回调函数中,
例如,修改响应的Content-Type信息头:
$.ajax({url: "http://fiddle.jshell.net/favicon.png",beforeSend: function ( xhr ) {xhr.overrideMimeType("text/plain; charset=x-user-defined");} }).done(function ( data ) {if( console && console.log ) {console.log("Sample of data:", data.slice(0, 100));} });
从 jQuery 1.5 开始,$.ajax()
返回的jqXHR对象 实现了 Promise 接口, 使它拥有了 Promise 的所有属性,方法和行为。(见Deferred object获取更多信息)。
为了让回调函数的名字统一,便于在$.ajax()
中使用。jqXHR也提供.error()
.success()
和.complete()
方法。这些方法都带有一个参数,该参数是一个函数,此函数在 $.ajax()
请求结束时被调用,并且这个函数接收的参数,与调用 $.ajax()
函数时的参数是一致。这将允许你在一次请求时,对多个回调函数进行赋值,甚至允许你在请求已经完成后,对回调函数进行赋值(如果该请求已经完成,则回调函数会被立刻调用)。
更多的更多大家还是仔细参考API吧
转载于:https://www.cnblogs.com/aaronjs/p/3798868.html
jQuery源码分析系列(37) : Ajax 总结相关推荐
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- [转]jQuery源码分析系列
文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...
- jQuery源码分析系列:.domManip() .buildFragment() .clean()
.domManip(args,table,callback):是jQuery DOM操作的核心函数,可以扩展出如下方法: append/appendTo: prepend/prependTo: b ...
- jQuery源码分析系列:属性操作
属性操作 1.6.1相对1.5.x最大的改进,莫过于对属性.attr()的重写了.在1.6.1中,将.attr()一分为二: .attr()..prop(),这是一个令人困惑的变更,也是一个破坏性的升 ...
- jQuery源码分析系列 : 整体架构
query这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery又给扫一遍 我也不会照本宣科的翻译源码,结合自己的实际经验一起拜读吧! ...
- jQuery源码分析系列:事件模块概述
jQuery的事件模块是较复杂的,前面仅仅提到了对事件对象的包装.即统一了一些兼容性的问题.这篇会综述下jQuery的整个事件模块.后面会详细分析jQuery.event.add/jQuery.eve ...
- jQuery源码分析系列目录
jQuery是对JavaScript的最佳实践的产物,这么好的东西阅读后一定会有感悟,还是要拿出来和大家分享滴,从今天开始阅读jQuery并将笔记进行记录,每天更新 1. 简便使用jQuery-源码阅 ...
- jQuery源码分析系列(二)Sizzle选择器引擎-上
前言 我们继续从init()方法中的find()方法往下看, jQuery.find = Sizzle; ...find: function (selector) {/** ... */ret = t ...
- jQuery源码分析系列(一)初识jQuery
一个工厂 (function(global, factory){"use strict"// operation_1 })(typedef window !== "und ...
最新文章
- 安全、稳定、可靠甲骨文定义PaaS新时代
- 2021-04-10 【数据库导数】数字类型的列如果位数过长,变为科学计数法问题
- vivado下创建基本时序周期约束
- php在u盘里运行,在U盘中直接运行Linux的详细步骤
- cocos 层级渲染与管理
- 小组取什么名字好_如何给公司取一个好名字?让你的公司脱颖而出
- DATEDIF函数:
- MFC 菜单栏添加方法
- npm查看依赖包报错:npm ERR! extraneous解决!!
- 云计算的三种服务模式的讲解
- spring boot验证码的实现
- 已经开源的阿里云播放器的播放内核
- 【win10蓝屏】记录一下,随机蓝屏,开机蓝屏,使用中蓝屏的经历
- 总结下利用python赚钱的方法,在闲余时间月赚2k-5k
- C#面试经历分享(好好看,好好学)
- 【2022 CCF BDCI 文心大模型创意项目】乐享词话—诗词意境辅助记忆工具
- Android之重写与重载
- 总谐波失真--THD
- Web 编程期中大作业
- android倒计时停止,Android 使用 Timer 做倒计时。实现开始 (start),取消 (cancel),暂停 (pause),重开 (resume)功能...
热门文章
- 同一个网站别人能打开我打不开_做网站建设需要注意的五大事项
- 菏泽中考报名不报计算机,2020菏泽中考报名人数:94559人
- 一个数三位立方和相加等于本身_【题解信奥】打印水仙花数(粉丝求助)
- bool转nsnumber ios_iOS 的 NSNumber(对基本数据类型) NSValue(对结构体) 的装箱
- php编译7教程,LANMP系列教程之php编译安装CentOS7环境
- java user.dir 设置_使用java系统属性user.dir读取配置文件
- matlab电路环流,基于MATLAB的单芯电缆金属护套环流分析研究
- python 打包图标_Python打包成exe文件很难?一分钟即可学会,并添加图标!
- jenkins页面中英文切换配置
- Redis Sentinel--运维管理