• jQuery源码分析系列(33) : AJAX中的前置过滤器和请求分发器


    jQuery1.5以后,AJAX模块提供了三个新的方法用于管理、扩展AJAX请求,分别是:

    1.前置过滤器 jQuery. ajaxPrefilter

    2.请求分发器 jQuery. ajaxTransport,

    3.类型转换器 ajaxConvert

    源码结构:

    jQuery.extend({
    
        /**
         * 前置过滤器
         * @type {[type]}
         */
        ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
    
        /**
         * 请求分发器
         * @type {[type]}
         */
        ajaxTransport: addToPrefiltersOrTransports(transports),
    
        
         ...........................
    });

    可见这2个方法是通过私有方法addToPrefiltersOrTransports通过curry手段构造的,分别是保持了prefilters与transports的引用


    来个简单的模拟这个结构

    var prefilters = 2;
    
    var addToPrefiltersOrTransports = function(prefilters) {
        return function(b) {
            return prefilters + b;
        }
    }
    
    var ajaxPrefilter = addToPrefiltersOrTransports(prefilters)
    
    ajaxPrefilter(1) //3

    可见ajaxPrefilter就维持了addToPrefiltersOrTransports返回函数的引用了,这种就是闭包的手法了,这也是JS的开发人员都需要掌握的

    好处就是合并多个参数,当然因为维持引用代价就是一点点性能消耗

    当然jQuery不是传递的简单类型处理,还可以传递的一个引用类型的回调函数,所以针对ajaxPrefilter方法放闭包构件就需要做一些处理了

    填充prefilters处理器

    var prefilters = {};
    
    var addToPrefiltersOrTransports = function(structure) {
    
        return function(func) {
            structure['*'] = func;
        }
    }
    
    var ajaxPrefilter = addToPrefiltersOrTransports(prefilters)
    
    
    ajaxPrefilter(function(options){
        return {
            send:function(){
    
            },
            callback:function(){
    
            }
        }
    })

    其实说白了就是把对应的方法制作能函数的形式填充到prefilters或者transports对应的处理包装对象中

    要用的时候直接执行,每个函数都保持着各自的引用

    这种写法的好处自然是灵活,易维护,减少代码量

    还有我们经常的使用的,jQuery的代码很简练,比如合并多个方法的创建等等

    jQuery.each([
            "tabIndex",
            "readOnly",
            "maxLength",
            "contentEditable"
        ], function() {
            jQuery.propFix[this.toLowerCase()] = this;
        });

    所以此时的prefilters中的结构就是

    prefilters = {
            '*': function() {
                return {
                    send: function() {
    
                    },
                    callback: function() {
    
                    }
                }
            }
        }

    回归重点,那么引入ajaxPrefilter与ajaxTransport的作用是干嘛?

    前置过滤器和请求分发器在执行时,分别遍历内部变量prefilters和transports,这两个变量在jQuery加载完毕后立即初始化,从过闭包的方法填充这个2个对象

    ajaxPrefilter与ajaxTransport都是通过inspectPrefiltersOrTransports构建器

    prefilters中的前置过滤器在请求发送之前、设置请求参数的过程中被调用,调用prefilters的是函数inspectPrefiltersOrTransports;

    巧妙的是,transports中的请求分发器在大部分参数设置完成后,也通过函数inspectPrefiltersOrTransports取到与请求类型匹配的请求分发器:

    function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
    
        var inspected = {},
            seekingTransport = (structure === transports);
    
        function inspect(dataType) {
            var selected;
            inspected[dataType] = true;
            jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) {
                var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
                if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
                    options.dataTypes.unshift(dataTypeOrTransport);
                    inspect(dataTypeOrTransport);
                    return false;
                } else if (seekingTransport) {
                    return !(selected = dataTypeOrTransport);
                }
            });
            return selected;
        }
    
        return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
    }

    遍历structure[dataType]数组,并执行回调
    prefilterOrFactory为函数数组元素
    执行该函数如果返回的结果dataTypeOrTransport是字符串且时prefilters且没有被inspected过
    就给options.dataTypes数组头部添加该字符串
    继续递归dataTypeOrTransport(当我们使用json/jsonp的时候会返回“script”,于是会执行“script”相关的回调)
    如果是transport就返回dataTypeOrTransport的假结果


    前置过滤器 prefilters

    简单的说就是一种hack的做法,只是说比起事件的那种hack写的手法实现更为高明

    我们可以看看针对prefilters的方法其实就是dataType为 script,json,jsonp的处理

    当我们动态加载脚本文件比如

    $.ajax({
        type     : "GET",
        url      : "test.js",
        dataType : "script"
    });

    所以在inspectPrefiltersOrTransports方法中prefilters[script]能找到对应的处理方法,所以就会执行

    例如script的hack,要强制加上处理缓存的特殊情况和crossDomain

    因为设置script的前置过滤器,script并不一定意思着跨域

    跨域未被禁用,强制类型为GET,不触发全局时间

    jQuery.ajaxPrefilter("script", function(s) {
        if (s.cache === undefined) {
            s.cache = false;
        }
        if (s.crossDomain) {
            s.type = "GET";
        }
    });

    所以prefilters就是在特定的环境针对特定的情况做一些必要的兼容的处理


    请求分发器 transports

    请求分发器顾名思义发送请求,那么底层的ajax发送请求是通过send方法

    xhr.send();

    但是jQuery对send方法做了拆分,把对应的处理放到了transports中了

    那么transports对象也是类似前置处理器通过jQuery.ajaxTransport构建

    例如script,send,abort方法

    返回出transports方法

    transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
  • 相关阅读:
    弹出 提示窗口 背景显示灰色 可移动 模板
    rar文件的格式信息描述(中英文对照)
    android学习笔记48_实现软件国际化,实现文字国际化,和图片国际化
    php 7.2 安装 mcrypt 扩展
    laraveladmin 安装(总结)
    Laravel 精选资源大全
    Laravel 出现 No application encryption key has been specified
    Laravel5.5/6 报错call to undefined function openssl cipher iv length()
    一起谈.NET技术,Silverlight 游戏开发小技巧:动感小菜单2 狼人:
    一起谈.NET技术,你应该知道的15个Silverlight诀窍 狼人:
  • 原文地址:https://www.cnblogs.com/aaronjs/p/3777292.html
Copyright © 2020-2023  润新知