博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
zepto源码ajax模块学习
阅读量:7045 次
发布时间:2019-06-28

本文共 5120 字,大约阅读时间需要 17 分钟。

在学习zepto的源码的时候,不得不称赞这些人的厉害,我虽然能看明白,但是要我写,估计吭哧吭哧写不出来。虽然现在很少人使用zepto了,但是学习这些源码我相信每次看都能给咱们不同的感受。Deferred对象待会讲,deferred我认为是zepto设计最巧妙的地方。先来看zepto的ajax模块。

;(function($){  var jsonpID = +new Date();  function triggerAndReturn(context, eventName, data) {    var event = $.Event(eventName);    $(context).trigger(event, data);    return !event.isDefaultPrevented();  }})

这里为什么文件开头都要使用';'这是因为在对多个js文件进行打包的时候,如果使用换行分隔代码,当合并压缩多个文件之后,换行符会被删掉,连在一起可能出错,加上分号就保险了。

jsonpID在跨域jsonp的时候会使用到,这是为了禁止使用cache。triggerAndReturn()的目的在于创建一个Event事件,然后在context触发他,如果默认行为被取消了,则返回false。

$.ajaxSettings = {  type: 'GET',  success: empty,  xhr: function () {    return new window.XMLHttpRequest()  },  cache: true,  crossDomain: false}

这是ajax的初始化,默认是GET请求,xhr是新建的XMLHttpRequest()对象,cache表示浏览器是否应该被允许缓存GET响应。crossDomain表示是否可以来自另外一个域。

下面来看看最核心的$.ajax方法。

$.ajax = function (options) {      var settings = $.extend({}, options || {}),        deferred = $.Deferred && $.Deferred(),        urlAnchor, hashIndex      for (key in $.ajaxSettings)        if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]      ajaxStart(settings)    ...  }

首先传入options,然后将传入的options存储到本地,deferred咱们暂时可以把它看成一个promise对象,遍历$.ajaxSettings,如果用户没有设置里边有的属性,那就使用默认的属性。然后调用ajaxStart开始的函数。

if (!settings.crossDomain) {  urlAnchor = document.createElement('a');  urlAnchor.href = settings.url;  urlAnchor.href = urlAnchor.href;  settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host)}

这里首先crossDomain为false的情况下,进入该逻辑,通过判断我们传入的url和当前window.location.href做对比,判断是不是跨域。

if ((hashIndex = settings.url.indexOf('#')) > -1) settings.url = settings.url.slice(0, hashIndex)var dataType = settings.dataType,  hasPlaceholder = /\?.+=\?/.test(settings.url);if (hasPlaceholder) dataType = 'jsonp';if (settings.cache === false || (    (!options || options.cache !== true) &&    ('script' == dataType || 'jsonp' == dataType)  ))  settings.url = appendQuery(settings.url, '_=' + Date.now())function appendQuery(url, query) {  if (query == '') return url;  return (url + '&' + query).replace(/[&?]{1,2}/, '?')}if ('jsonp' == dataType) {  if (!hasPlaceholder)    settings.url = appendQuery(settings.url,      settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?')  return $.ajaxJSONP(settings, deferred)}

如果我们没有传入url,那么url就是window.location.href。'#'代表网页中的一个位置,右边的字符,就是该位置的标识符,#是用来指导浏览器动作的,对浏览器没有用,所以在截取url的时候,没必要把后面的部分传给服务器。hasPlaceholder这里的正则表达式,用于匹配类似'?name=?'这种字符串,如果hasPlaceholder为true,则dataType为jsonp。下面的时不使用留在缓存的数据,第一种是设置cache为false,或者dataType为script和jsonp的情况,需要在url后面添加事件。下面是appendQuery方法,就是把字符串拼接到url后边,但是需要把'&'替换成'?'。如果我们的请求是jsonp请求,需要在url后面添加一些callback=?这种参数。

var mime = settings.accepts[dataType],    headers = {},    setHeader = function(name, value) {headers[name.toLowerCase()] = [name, value]},    protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,    xhr = settings.xhr(),    nativeSetHeader = xhr.setRequestHeader,    abortTimeoutif (deferred) deferred.promise(xhr);if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest');setHeader('Accept', mime || '*/*')if (mime = settings.mimeType || mime) {  if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]  xhr.overrideMimeType && xhr.overrideMimeType(mime)}

settings中的accepts表示从服务器请求的MIME类型,指定dataType的值,包括script、json、xml、html、text。mime存储的就是类似'application/json'的字符串。protocol就是匹配咱们类似'http://'的这种协议。

如果deferred存在,就把xhr转换为deferred对象。接着看下去,如果不是跨域的,那就是ajax请求。然后后面的判断条件查了一下是针对一些mozillar浏览器进行修正(有个问题就是他们上哪儿知道的用这种方式来修正啊)。

xhr.onreadystatechange = function() {  if (xhr.readyState == 4) {    xhr.onreadystatechange = empty    if (/*如果成功*/){      // 对返回结果进行处理    }  }}xhr.open(settings.type, settings.url, async, settings.username, settings.password)

没什么难的,就是根据传入的参数不同进行处理。

$.param

这个函数的作用在于序列化传入对象,下面是他的代码:

$.param = function (obj, traditional) {   var params = []   params.add = function (key, value) {     if ($.isFunction(value)) value = value()     if (value == null) value = ""     this.push(escape(key) + '=' + escape(value))   }   serialize(params, obj, traditional)   return params.join('&').replace(/%20/g, '+') }

传入一个对象,和一个标记,这个traditional表示激活传统的方式通过$.param来得到data。首先定义一个空数组,如果在上面添加方法,这个方法的主要作用向params里边添加序列化的对象,escape=encodeURIComponent,然后调用serialize,将obj对象添加到params中,最后返回将params数组用'&'拼接,然后这里的%20表示空格,意思是将空格替换成'+'

serialize

下面是代码

function serialize(params, obj, traditional, scope) {  var type, array = $.isArray(obj),    hash = $.isPlainObject(obj)  $.each(obj, function (key, value) {    type = $.type(value)    if (scope) key = traditional ? scope :      scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']'    // handle data in serializeArray() format    if (!scope && array) params.add(value.name, value.value)    // recurse into nested objects    else if (type == "array" || (!traditional && type == "object"))      serialize(params, value, traditional, key)    else params.add(key, value)  })}

params是带有add方法的数组,遍历obj的键值对,属性值可能是对象也可能是数组或者字符串分别进行处理。如果obj的某个属性值是对象或者数组,scope就代表是该属性,那么这时候向params传入的key就需要变化,变成类似'a[b]'这里的b是obj的某个属性值是对象的一个属性。

转载地址:http://kxhal.baihongyu.com/

你可能感兴趣的文章
centos7 基于pxe安装系统
查看>>
节假日批量设置的C#.NET程序代码参考 荐
查看>>
Vim键盘布局
查看>>
Exchange2010管理控制台无法安装
查看>>
android用户界面-组件Widget-网络视图WebView
查看>>
KVM 存储虚拟化 - 每天5分钟玩转 OpenStack(7)
查看>>
iAMT无法连接,该怎么办?
查看>>
lintcode二叉树的锯齿形层次遍历 (双端队列)
查看>>
ADSL技术概述
查看>>
CentOS下NFS服务器配置实例
查看>>
RHEL5.4部署中央日志服务器之rsyslog+loganalyzer
查看>>
酷派7728软件安装到外置SD卡上的方法,也适用于联想s850e等
查看>>
步步为营VS 2008 + .NET 3.5(10) - DLINQ(LINQ to SQL)之调用存储过程的添加、查询、更新和删除...
查看>>
windows Compiler toolchain env
查看>>
使用RMAN的DUPLICATE克隆Oracle10gR2 数据库
查看>>
人生中该放弃的八样东西
查看>>
python的动态加载机制??
查看>>
OutOfMemoryError系列(1): Java heap space
查看>>
SCOM 2012系列②安装部署SCOM
查看>>
在JavaScript中操作Cookie
查看>>