资讯专栏INFORMATION COLUMN

zepto源码ajax模块学习

hizengzeng / 1900人阅读

摘要:对象待会讲,我认为是设计最巧妙的地方。在跨域的时候会使用到,这是为了禁止使用。的目的在于创建一个事件,然后在触发他,如果默认行为被取消了,则返回。这是的初始化,默认是请求,是新建的对象,表示浏览器是否应该被允许缓存响应。

在学习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,
    abortTimeout

if (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的某个属性值是对象的一个属性。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96676.html

相关文章

  • Zepto源码Ajax模块

    摘要:私有变量用来临时存放配置中的,即请求成功后执行的回调函数名,该配置可以为类型。是根据配置得出的回调函数名。接下来,将的占位符,替换成回调函数名,最后将插入到页面中,发送请求。 Ajax 模块也是经常会用到的模块,Ajax 模块中包含了 jsonp 的现实,和 XMLHttpRequest 的封装。 读 Zepto 源码系列文章已经放到了github上,欢迎star: reading-...

    Crazy_Coder 评论0 收藏0
  • Zepto源码之Stack模块

    摘要:读源码系列文章已经放到了上,欢迎源码版本本文阅读的源码为改写原有的方法模块改写了以上这些方法,这些方法在调用的时候,会为返回的结果添加的属性,用来保存原来的集合。方法的分析可以看读源码之模块。 Stack 模块为 Zepto 添加了 addSelf 和 end 方法。 读 Zepto 源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的...

    crossea 评论0 收藏0
  • zepto源码分析之form模块

    摘要:形如源代码在的原型上添加了相关方法。类似源代码每个表单的和都通过编码最后通过符号分割有了的基础,就是将相应的和都通过编码,然后用符号进行分割,也就达到了我们要的结果。 前言 JavaScript最初的一个应用场景就是分担服务器处理表单的责任,打破处处依赖服务器的局面,这篇文章主要介绍zepto中form模块关于表单处理的几个方法,serialize、serializeArray、sub...

    Muninn 评论0 收藏0
  • Zepto源码之assets模块

    摘要:模块是为解决移动版加载图片过大过多时崩溃的问题。因为没有处理过这样的场景,所以这部分的代码解释不会太多,为了说明这个问题,我翻译了这篇文章作为附文怎样处理移动端对图片资源的限制,更详细地解释了这个模块的应用场景。 assets 模块是为解决 Safari 移动版加载图片过大过多时崩溃的问题。因为没有处理过这样的场景,所以这部分的代码解释不会太多,为了说明这个问题,我翻译了《How to...

    thursday 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<