Jquery 实现原理之 Ajax

一:Jquery Ajax底层接口有$.ajaxPrefilters、$.ajaxTransport、$.ajaxSettings、$ajaxSetup、$ajaxSettings;

  其中$.ajaxPrefilters $.ajaxTransport是通过inspectPrefiltersOrTransports构造器来创建的;

$.ajaxPrefilters:是一个前置过滤器,在每个请求被$.ajaxTransport()和$.ajax()处理之前调用,设置自定义ajax选项或者修改现有的选项,简单说就是hack的  做法,但是比事件处理的hack的手法更加高明。可以用来处理参数,注册回调等。

例如:改变代理服务器的域请求

1 $.ajaxPrefilter("+*", function( options ) {
2   if ( options.crossDomain ) {
3     options.url = "http://mydomain.net/proxy/" + encodeURIComponent( options.url );
4     options.crossDomain = false;
5   }
6 });

 

$.ajaxTransport:是一个请求分发器,是发送请求的具体实现,比如xhr就用xmlhttprequest来实现,script就是通过head中插入script标签来实现.

例如:用来拦截发送的请求

 1 $.ajaxTransport("+*", function(options, originalOptions, jqXHR) {
 2         return {
 3             send: function(headers, completeCallback) {
 4                 var status = 404;
 5                 var statusText = "error";
 6                 var response = {
 7                     text: ""
 8                 };
 9                 var item = {            
10                     url: "/paapi/v1/datapoints/pa",
11                     data: data.groupsdatapoint
12                 };
13                 if (!item) {
14                     console.log("require mock data: \n" + originalOptions.url);
15                 } else {
16                     status = 200;
17                     statusText = "ok";
18                     var data = item.data;
19                     response.text = data;
20                 }
21                 setTimeout(function() {
22                     completeCallback(status, statusText, response);
23                 }, 0);
24             }
25         };
26     });

二: ajax的实现

  实现ajax的目的是什么?

实现ajax的目的主要是对不同的dataType的具体处理和实现,比如'jsonp'应该怎么处理,'script'怎么处理,'*'怎么处理;

对此ajax模块的做法是,提供一个基本的模块ajax,然后通过插件形式来实现对不同dataType的处理。

ajax暴露ajaxPrefilter: addToPrefiltersOrTransports( prefilters ) , ajaxTransport: addToPrefiltersOrTransports( transports )是给插件用的,可以注册自己的dataType处理函数。

其中prefilters={'jsonp': function() {}, '*': function(){}, 'script':function(){}}可能是这样的,ajax在每个请求发送之前,根据dataType调用prefilters中的函数进行预处理,然后调用transport中的对应函数来发送请求。

addToPrefiltersOrTransports()方法如下:

 1 function addToPrefiltersOrTransports(structure) {
 2 
 3      // dataTypeExpression is optional and defaults to "*"
 4      return function(dataTypeExpression, func) {
 5 
 6           if (typeof dataTypeExpression !== "string") {
 7                func = dataTypeExpression;
 8                dataTypeExpression = "*";
 9           }
10 
11           var dataType,
12                i = 0,
13                dataTypes = dataTypeExpression.toLowerCase().match(rnotwhite) || [];
14 
15           if (jQuery.isFunction(func)) {
16                // For each dataType in the dataTypeExpression
17                while ((dataType = dataTypes[i++])) {
18                     // Prepend if requested
19                     if (dataType[0] === "+") {
20                          dataType = dataType.slice(1) || "*";
21                          (structure[dataType] = structure[dataType] || []).unshift(func);
22 
23                          // Otherwise append
24                     } else {
25                          (structure[dataType] = structure[dataType] || []).push(func);
26                     }
27                }
28           }
29      };
30 }

该函数功能就是把某一个dataType对应的处理函数func存进structure中,实际就是一个简单的注册事件。

 1 // Base inspection function for prefilters and transports
 2 function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
 3 
 4      var inspected = {},
 5           seekingTransport = (structure === transports);
 6 
 7      function inspect(dataType) {
 8           var selected;
 9           inspected[dataType] = true;
10           jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) {
11                var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
12                if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
13                     options.dataTypes.unshift(dataTypeOrTransport);
14                     inspect(dataTypeOrTransport);
15                     return false;
16                } else if (seekingTransport) {
17                     return !(selected = dataTypeOrTransport);
18                }
19           });
20           return selected;
21      }
22 
23      return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
24 }
25 }

该代码时取调用dataType对应的prefilters和transports函数而已。

 

Ajax完成一部请求的全过程:

  • 创建了一个jqXHR对象,这个对象就是ajax的返回值
  • 用deferred对象封装jqXHR对象,因此可以实现链式的异步操作:xhr.complete(x).success(x).errorl(x),这里的complete,success和error就是promise对象的add, done和fail的别名而已。
  • 调用函数inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ),那些插件注册的prefilters函数就在这里被调用了。
  • 做了一大对后续的处理,比如设置header参数,设置缓存cache
  • 调用inspectPrefiltersOrTransports( transports, s, options, jqXHR )函数发送请求
  • 定义了done函数,当请求发送结束之后做后续处理,包括调用convert转换结果、设置statusText,调用deferred.resolveWith触发异步回调等
  • 最后返回了jqXHR对象

 

posted @ 2016-04-15 15:47  快饿死的鱼  阅读(1200)  评论(0编辑  收藏  举报