资讯专栏INFORMATION COLUMN

如何更有效的在中大型项目中管理ajax请求

ACb0y / 2269人阅读

摘要:前言在中大型的前端应用里面项目里面通常包夹了大量的请求,通常情况这些请求夹杂在业务代码里面拓展维护的成本比较大。测试代码及源码下载在中归纳本篇文章是通过对请求调用前,调用后的统一处理来更有效的控制这些请求类似于面向切面的思想。

前言

在中大型的前端应用里面项目里面通常包夹了大量的ajax请求,通常情况这些请求夹杂在业务代码里面,拓展维护的成本比较大。

如要改整个项目的url前缀(后端把接口路径统一加个assets或者http换成https),或者要改请求的类型get换post,亦或者统一加个CSRFToken,我们该当如何,手动一个个把自己一头扎进业务代码里面去修改吗?

此时不妨试试用一个js去统一管理这些ajax请求。

分析

以下是我们使用ajax请求的方式

调用请求的时候拼装url,在较多ajax请求的时候面,维护拓展就变得非常的艰难
本文章想法是把url抽象成不同类型的参数

将url分为三类:

公共型参数: 每个url都共用的部分 如http类型,url前缀,mockurl前缀,token等

配置型参数: 每个url都不一样的,但可以提前预知的部分,如uri地址,ajax请求方式(get/post)

业务型参数: 具体进业务场景方能算出来的参数 如test=xxx(xxx的值只有程序运行的时候才知道值)

公共型参数和配置型参数可以在项目初始化的时候通过逻辑控制并存起来,
业务型参数在具体调用的时候在具体的业务场景获取。
在通过统一的ajax请求获取资源

流程图

统一的ajax请求,可以在失败之后,统一抛出异常,成功之后统一改变获取数据的结构等等好处

代码实现 简单工厂存储url参数对象

简单工程创建 参数实例,并将实例对象存储在context内部

    (function (root,$) {
    //简单工厂生成项目统一的ajax参数对象
    var DBFactory = {
        __: {},
        //可有业务代码设置mockUrl,prefixUrl等
        set: function (key, value) {
            this.__[key] = value;
        },
        get: function (key) {
            return this.__[key];
        },
        create: function (name, methods) {
            // 禁止创建重名的DB实例
            if (this.context[name]) {
                console.warn("DB: "" + name + "" is existed! ");
                return;
            }
            return this.context[name] = new DB(name, methods);
        },
        // 存储db实例
        context: {
            
        }
    };


    //DB构造函数 负责构造ajax参数对象
    function DB(DBName, methods) {
        var t = this;
        t.cache = {};
        $.each(methods, function (method, config) {
            if (typeof config === "function") {
                t[method] = config;
                return;
            }

            t[method] = function (query) {
                var cfg = {};

                cfg.method = method;

                cfg.DBName = DBName;

                cfg.mockUrl = config.mockUrl;

                // 如果设置了`mock`代理
                if (cfg.mockUrl && typeof DBFactory.__.mockProxy === "function") {
                    cfg.mockUrl = DBFactory.__.mockProxy(cfg.mockUrl);
                }
                //合并参数
                cfg.query = $.extend({}, config.query || {}, query || {});
                //判断是否mock
                cfg.isMock = config.url ? false : true;
                //url前缀供getUrl计算url
                t.urlPrefix = DBFactory.get("urlPrefix") || "";
                //url
                cfg.url = cfg.isMock ? cfg.mockUrl : (t.getUrl(config.url) || cfg.mockUrl);
                // 是否是全局只获取一次
                cfg.once = typeof config.once === "boolean" ? config.once : false;
                // 数据缓存,如果`once`设置为true,则在第二次请求的时候直接返回改缓存数据。
                t.cache[method] = t.cache[method] || null;

                cfg.jsonp = config.jsonp || false;

                cfg.type = config.type || "POST";
                return request(cfg, t);
            };
        });
    }

    /**
     * 获取正式接口的完整`url`
     * 如果通过`DB.set("urlPrefix", "https://xxx")`设置了全局`url`的前缀,则执行补全
     */
    DB.prototype.getUrl=function (url) {
        if (this.urlPrefix && url.indexOf("http") !== 0 && url.indexOf("//") !== 0) {
            return this.urlPrefix + url;
        } else {
            return url;
        }
    };

    /**
     *
     * @param cfg  属性对象提供给ajax修改请求属性
     * @param db   db提供缓存
     * @returns  ajax promise
     */
    function request(cfg, db) {
        var defer = $.Deferred();
        if (cfg.once && db.cache[cfg.method]) {
            defer.resolve(db.cache[cfg.method]);
        } else {
            var ajaxOptions = {
                url: cfg.url,
                data: cfg.query,
                success: function (resp) {
                    //cfg.once && (db.cache[cfg.method] = resp);
                    defer.resolve(resp);
                },
                error: function (error) {
                    defer.reject({
                        fail:true,
                        msg:  error
                    });
                }
            };

            if (cfg.jsonp === true) {
                ajaxOptions.dataType = "jsonp";
            } else {
                ajaxOptions.dataType = "json";
                ajaxOptions.type = cfg.type;
            }

            $.ajax(ajaxOptions);
        }
        return defer.promise();
    };
    root.DBFactory = DBFactory;
})(this,$);
配置参数

db.js 负责注册ajax请求,并全局的设置url前缀,是否启用mockurl,对不同请求配置不同的请求方式,是否jsonp等

(function (DBF) {
var isOnline = false;
// 设置全局的`url`前缀
    var urlPrefixForLocal = location.protocol + "//" + location.host+"/";
    if (!isOnline) {
        DBF.set("urlPrefix", urlPrefixForLocal);
    } else {
        DBF.set("urlPrefix", "/trs");
    }

// MockProxy mock 数据服务器(node/php代理)代理,以跨过同源检测
    DBF.set("mockProxy", function (mockUrl) {
        return "/mock?url=" + mockUrl
    });

    DBF.create("Test", {
        get: {
            type: "GET",
            // jsonp: true,
            url: "example/ajax-data/data.json"
            // mockUrl: urlPrefixForLocal + "/ajax-data/data.json",
            //once: true
        }
    });

    DBF.create("GetPersonInfo", {
        get: {
            type: "GET",
            url: "getMySimpleInfo.json",
            once: true
        }
    });

    window.DB = DBF.context;
})(window.DBFactory);
开始测试 加上请求的资源

调用代码

ajax的真正调用者,通过DB.xxx 拿到参数对象后以get的形式触发实际的ajax请求,并附带业务代码里面的参数。

            $(document).ready(
            function () {
                var DB = window.DB;
                var promise1 = $.when(DB.Test.get({test: true}));
                var promise2 = $.when(DB.GetPersonInfo.get());
                promise1.then(
                        function (res) {
                            console.log(res)
                            $("#promise1").html("promise1:"+res.data);
                        }, function (error) {
                            console.log(error);
                        });

                promise2.then(
                        function (res) {
                            console.log(res)
                        }, function (error) {
                            $("#promise2").html("promise2:"+error.msg.responseText);
                        });
            }
    )
   
运行结果

promise1 拿data.json 返回成功
promise2 拿getMySimpleInfo.json 资源未获取到,返回失败

本篇文章是以jquery形式展示的,但稍事修改也是可以在backbone,react等框架内使用。
测试代码及源码下载在https://github.com/laughing-p... 中

归纳 本篇文章是通过对ajax请求调用前,调用后的统一处理来更有效的控制这些请求,类似于面向切面的思想。

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

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

相关文章

  • 翻译 | React AJAX最佳实践

    摘要:作者沪江前端开发工程师本文原创翻译,有不当的地方欢迎指出。管理数据,而提供服务器上的数据,因此应用于处理网络请求。结论使用建立的应用都是模块化的会成为其中一个模块,库是另一个模块。原文原创新书移动前端高效开发实战已在亚马逊京东当当开售。 作者:Oral (沪江Web前端开发工程师)本文原创翻译,有不当的地方欢迎指出。转载请指明出处。 当你问起有关AJAX与React时,老司机们首先就会...

    DirtyMind 评论0 收藏0
  • 如何正确的在项目接入微信JS-SDK

    摘要:进过下面的步骤,一步一步的配置,就可以让你正确的在项目中引入微信的。在进行了正确的微信文件引入后看上面在页面中调用如下代码就可以注入权限验证配置。可以通过微信提供的两个接口来进行事件回调。到这为止,微信的接入就完成了。 微信JS-SDK的功能 如果你点进来,那么我相信你应该知道微信的JS-SDK可以用来做什么了。微信的官方文档描述如下。 微信JS-SDK是微信公众平台面向网页开发者提供...

    ivyzhang 评论0 收藏0
  • ES6的异步编程:Generators函数+Promise:最强大的异步处理方式

    摘要:更好的异步编程上面的方法可以适用于那些比较简单的异步工作流程。小结的组合目前是最强大,也是最优雅的异步流程管理编程方式。 访问原文地址 generators主要作用就是提供了一种,单线程的,很像同步方法的编程风格,方便你把异步实现的那些细节藏在别处。这让我们可以用一种很自然的方式书写我们代码中的流程和状态逻辑,不再需要去遵循那些奇怪的异步编程风格。 换句话说,通过将我们generato...

    Taonce 评论0 收藏0
  • 杂篇 - Vue豆瓣系列文章

    摘要:起初,项目使用的是,其提供的方法用着比较爽,由于项目的很多数据来自豆瓣的,直接上简单方便,跨域什么的不考虑。跨域问题,上面已经介绍,在不能操控的豆瓣数据上,使用的是。 项目地址 在线演示 不识庐山真面目,只缘身在此山中。 大概一个月前,开源了Vue重构豆瓣移动端的项目,效果还可以,收到了很多小伙伴的反馈,话说是要写一些文章的,但迟迟没有动笔,估计小伙伴们等的花都谢了,拖延症是病,需要治...

    lijinke666 评论0 收藏0
  • 前端vue系列-起始篇 vue的基本认知

    摘要:管理后台,日常就是提交各种表单了,这部分现有的方案,比如表单提交或者收集信息提交。,可以用于前端开发的工程构建。带了人的前端团队,你的精力开始在配合公司其他部门做用户数据增长了。开始考虑使用的。       hi,大家伙,我是佛系大大,很高兴与你们一起沟通,学习,进步。        很久不更新博客了,现在回来再写博客,尽然是有些怀念的感觉,幸福的感觉。因为写博客,内心会很宁静,沉浸在自己的...

    I_Am 评论0 收藏0

发表评论

0条评论

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