如何更有效的在中大型項目中管理ajax請求

前言

在中大型的前端應用裏面項目裏面一般包夾了大量的ajax請求,一般狀況這些請求夾雜在業務代碼裏面,拓展維護的成本比較大。php

如要改整個項目的url前綴(後端把接口路徑統一加個assets或者http換成https),或者要改請求的類型get換post,亦或者統一加個CSRFToken,咱們該當如何,手動一個個把本身一頭扎進業務代碼裏面去修改嗎?html

此時不妨試試用一個js去統一管理這些ajax請求。前端

分析

如下是咱們使用ajax請求的方式
圖片描述node

調用請求的時候拼裝url,在較多ajax請求的時候面,維護拓展就變得很是的艱難
本文章想法是把url抽象成不一樣類型的參數react

將url分爲三類:

  • 公共型參數: 每一個url都共用的部分 如http類型,url前綴,mockurl前綴,token等jquery

  • 配置型參數: 每一個url都不同的,但能夠提早預知的部分,如uri地址,ajax請求方式(get/post)git

  • 業務型參數: 具體進業務場景方能算出來的參數 如test=xxx(xxx的值只有程序運行的時候才知道值)github

圖片描述

公共型參數和配置型參數能夠在項目初始化的時候經過邏輯控制並存起來,
業務型參數在具體調用的時候在具體的業務場景獲取。
在經過統一的ajax請求獲取資源ajax

流程圖

圖片描述

統一的ajax請求,能夠在失敗以後,統一拋出異常,成功以後統一改變獲取數據的結構等等好處json

代碼實現

簡單工廠存儲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請求調用前,調用後的統一處理來更有效的控制這些請求,相似於面向切面的思想。

相關文章
相關標籤/搜索