jQuery源码分析系列(30) : Ajax 总体结构

开头引用一段javascript

想起一句话:前端研究,研究个屁~ 的确如此呀。补充下联:前端设计,设计个屁~

前端目前最大的困境是,如 HTML 同样,不管你承不认可,市场上并不太须要 HTML 高手

其实这里引起一个问题:前端的价值到底是什么?将来应该如何发展?php

我我的以为仍是一个核心价值的问题,前端在漂亮的东西都是须要后端的数据支撑的,并且前端的绝大部分问题,其实都须要后端才能解决,就如我开发了三年的混合项目,虽然前端代码有3万行,可是后端一个数据拷贝失败,整个项目都是白搭css

固然这里我并不是要深刻这个话题,只是想代表尽量的提升自身的价值html

从前端的历史变动与发展过程来看,若是拿人类的历史来比喻,从最原始的刀耕火种以HTML静态结构为主的原始社会,到后来带有逻辑处理与服务器混搭交互的的石器时代以及最近几年流行的node.js,MVC,MVVM,Phonegap等衍生而来的东东让前端大跃进式的跳跃进入了一个新的工业时代,不到20年的时间web技术翻天覆地的变化前端

现在的前端进入了 MV* 时代,同时Ajax也带来了SPA,Node带来了全栈,这些都切实推进着前端往前发展java

优秀的前端一方面是完成的效率,另外一方面是可维护和可扩展性的提升带来的潜在价值,解放生产力,专一展示与业务逻辑,减小琐碎的兼容处理node

若是你使用一面大镜子做为冲浪板会发生什么?或许你会在较短的时间内征服海浪,可是你确定从心里深处明白,这不是冲浪的正确选择jquery

因此咱们不该该只要求本身仅仅停留在API的层次,若是能理解原理深刻设计,那么就将会跨上一个新的台阶css3

 


jQuery.Ajax作了那些事?web

咱们知道AJAX的底层实现实际上是很简单的.抛开IE不说,标准的w3c直接提供了XMLHttpRequest方法

关于AJAX基础请飞机 触碰jQuery:AJAX异步详解

咱们主要站在设计的角度理解,如何设计出低耦合高内聚的代码

jQuery对Ajax的处理主要体如今对浏览器兼容,数据的处理及过滤,各类事件的封装上

主要有如下几部分扩展:

提供快捷接口

提供底层接口

提供数据序列化

提供全局Ajax事件处理

具体使用请看API,这里再也不重复

 


分析下面一个demo

给document绑定ajaxStart,ajaxComplete回调事件

trigger绑定一个点击事件,发送ajax请求

点击trigger出发点以后,发送一个ajax请求,而且经过complete,done,ajaxStart, ajaxComplete返回状态回调

//全局事件触发
$(document).ajaxStart(function() {
    console.log(arguments)
}).ajaxComplete(function() {
    $(".log").text("Triggered ajaxComplete handler.");
});


$(".trigger").click(function() {
    //发送ajax请求
    //
    $.ajax({
        url: "php.html",
        context: document.body,
        complete: function() {
            console.log(this)
        }
    }).done(function() {
        console.log(this)
    });
});

这里实现比较特别的地方

针对ajax提供2种回调方式,内部的complete回调与外部的done回调

全局document上都能捕获到ajax的每一步的回调通知

换句话说,针对ajax的请求,每一步的状态,成功或者失败,咱们有3种方式能够获取,可是每一种仍是有各自的区别

1 ajax的参数回调

2 基于deferred方式的done回调

3 全局的的自定义事件的回调

 


从设计的层面上来考下,这种事件组合的方式是如何实现?有什么优点?

设计一:

tAjax({
    url: "php.html",
    complete: function(data) {
        console.log(data)
    }
})

若是要实现这种接口调用

那么咱们就须要封装下代码,把回调经过实参传递

var tAjax = function(config) {
    var url      = config.url;
    var complete = config.complete; 
    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('post', url);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                complete(xhr.responseText);
            }
        }
    }
    xhr.send();
}

这样设计能够看作相似工厂模式的封装,好处不用多说,在工厂模式里面包含了对象的建立等必要的逻辑,客户端根据传参选择动态的实例化相对的处理

对于客户端来去除了具体的依赖,固然tAjax你也能够看做一个外观模式提供的接口,其实就是隐藏了具体的复杂逻辑,提供一个简单的接口,从而下降耦合

 


设计二:

tAjax({
    url: "php.html",
    complete: function(data) {
        console.log(data)
    }
}).done(function(data){
    console.log(data)
})

在以前加入了一个done链式处理,固然这里done,实际上是deferred的一个成功处理通知,若是以前没有接触,你们去了解一下关于deferred的概念

咱们知道jQuery实现了链式,实现的原理没法就是返回自己对象的引用

var ajax = tAjax({
    url: "php.html",
    complete: function(data) {
        console.log(data)
    }
})

ajax.done(function(){
    
})

以上是分离的状况下,若是要合并成一条链式处理,只要在上一个方法中返回this便可

因此咱们改改

var tAjax = function(config) {

    var doneFn;

    var url      = config.url;
    var complete = config.complete; 
    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
    xhr.open('post', url);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                doneFn(xhr.responseText);
                complete(xhr.responseText);
            }
        }
    }

    xhr.send(xhr.responseText);

    return {
        /**
         * 返回一个done对象
         */
        done: function(ourfn) {
             doneFn = ourfn;
        }
    };
}

咱们返回了一个done对象,这里同样要是对象,由于链式的缘由,咱们看外部指定了内部的done,从而把外部函数给引用到内部的doneFn上 缓存起来

xhr.staturs 成功后一块儿执行

固然这种设计是有问题的,若是在done以后我在链式就确定不行,由于对象的引用错了,那么jQuery是如何处理?

 


设计三

提供document对象的全局处理

$(document).ajaxComplete(function() {
    console.log('ajax请求成功')
});


tAjax({
    url: "php.html",
    complete: function(data) {
         console.log(data)
    }
}).done(function(data){
    console.log(data)
})

这里的问题就是把ajax内部的事件,返回给全局捕获了,有点相似css3的全局动画事件

这里的设计其实最简单了由于自己之间没有什么耦合,就是发送一个事件给document便可

jQuery利用了trigger自定义事件触发的

globalEventContext.trigger("ajaxComplete", [jqXHR, s]);

具体每一种实如今后面的都会提到,在这里须要你们有个总体的印象,

 


总结:

经过读阅jQuery.ajax这段api咱们能够看到jQuery对ajax的处理作的至关的全面

首先咱们常常遇到某些耗时很长的javascript操做。其中,既有异步的操做(好比ajax读取服务器数据),也有同步的操做(好比遍历一个大型数组),它们都不是当即能获得结果的。

一般的作法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。

ajax引入了deferred方案,callback方案就是回调函数解决方案,从而处理耗时操做的问题,对那些操做提供了更好的控制,以及统一的编程接口

伴随Ajax请求会触发若干事件,咱们能够订阅这些事件并在其中处理咱们的逻辑。

在jQuery中有两种Ajax事件:局部事件和全局事件。

局部事件(回调函数),在$.ajax()方法的options参数中声明,能够用来设置请求数据和获取、处理响应数据。

全局事件,每次Ajax请求都会触发,它会向DOM中的全部元素广播,你只需为DOM中任意元素bind好全局事件即会触发(若绑定屡次,则会依次触发为事件注册的回调函数

除此以外,还提供了一系列的简化接口,好比.load ,还有直接对数据对象序列化的能力,对跨域的处理,contentType的修复等等

深刻待续。。。。。

相关文章
相关标签/搜索