亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > AJAX > 正文

對jquery的ajax進行二次封裝以及ajax緩存代理組件:AjaxCache詳解

2024-09-01 08:33:43
字體:
來源:轉載
供稿:網友
下面小編就為大家帶來一篇對jquery的ajax進行二次封裝以及ajax緩存代理組件:AjaxCache詳解。小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
 

雖然jquery的較新的api已經很好用了, 但是在實際工作還是有做二次封裝的必要,好處有:1,二次封裝后的API更加簡潔,更符合個人的使用習慣;2,可以對ajax操作做一些統一處理,比如追加隨機數或其它參數。同時在工作中,我們還會發現,有一些ajax請求的數據,對實時性要求不高,即使我們把第一次請求到的這些數據緩存起來,然后當相同請求再次發起時直接拿之前緩存的數據返回也不會對相關功能有影響,通過這種手工的緩存控制,減少了ajax請求,多多少少也能幫助我們提高網頁的性能。本文介紹我自己關于這兩方面問題的做法,歡迎交流和指正。

點擊 代碼下載 (注:因為用到了ajax,所以不能在file協議下運行,必須運行在http下)

1. 封裝jquery的ajax

其實這個部分的相關內容在之前的一篇博客引入過,只不過那里面只是引用,沒有詳細說明,另外ajax緩存代理組件的實現也是基于這個二次封裝之后的ajax組件的,所以有必要在這里對它詳細說明一下,雖然實現并不復雜(詳見注釋說明):

define(function (require, exports, module) {  var $ = require('jquery');  //根據關鍵的幾個參數統一創建ajax對象  function create(_url, _method, _data, _async, _dataType) {    //添加隨機數    if (_url.indexOf('?') > -1) {      _url = _url + '&rnd=' + Math.random();    } else {      _url = _url + '?rnd=' + Math.random();    }    //為請求添加ajax標識,方便后臺區分ajax和非ajax請求    _url += '&_ajax=1';    //返回jquery創建的ajax對象,以便外部拿到這個對象以后可以通過    //.done .fail .always來添加回調    //這么做是為了保留jquery ajax中好用的部分    return $.ajax({      url: _url,      dataType: _dataType,      async: _async,      method: _method,      data: _data    });  }  //ajax就是本組件全局唯一的實例,它的實例方法通過后面的循環代碼添加  //methods對象配置ajax各個實例方法的參數:  //name: 方法名稱  //method: http請求方法,get or post  //async: 發送請求時是否異步  //dataType: 返回的數據類型,html or json  var ajax = {},    methods = [      {        name: 'html',        method: 'get',        async: true,        dataType: 'html'      },      {        name: 'get',        method: 'get',        async: true,        dataType: 'json'      },      {        name: 'post',        method: 'post',        async: true,        dataType: 'json'      },      {        name: 'syncGet',        method: 'get',        async: false,        dataType: 'json'      },      {        name: 'syncPost',        method: 'post',        async: false,        dataType: 'json'      }    ];  //由于二次封裝需要對外提供的每個實例方法創建ajax的邏輯是相同的  //所以通過這種方式統一定義各個實例方法  //關鍵代碼為下面代碼中的那個立即調用的函數  //它返回了一個新的閉包函數作為實例方法  for (var i = 0, l = methods.length; i < l; i++) {    ajax[methods[i].name] = (function (i) {      return function () {        /**         * 每個實例方法接收三個參數         * 第一個表示要請求的地址         * 第二個表示要提交到后臺的數據,是一個object對象,如{param1: 'value1'}         * 第三個表示后臺返回的數據類型,最最常用的就是html or json,絕大部分情況下這個參數不用傳,會使用methods里面定義的dataType         */        var _url = arguments[0],          _data = arguments[1],          _dataType = arguments[2] || methods[i].dataType;        return create(_url, methods[i].method, _data, methods[i].async, _dataType);      }    })(i);  }  return ajax;});
這個Ajax組件主要做的事情是: 
1)統一提供隨機數參數和ajax請求標識; 
2)對jquery的api進行了包裝,對外提供的方法更加清晰明了。

使用方式:

define(function (require, exports, module) {  var Ajax = require('mod/ajax');  //以GET方式請求html內容  Ajax.html('html/demo', {    param1: 'value1',    param2: 'value2'  }).done(function(response){    //請求成功的回調  }).fail(function(){    //請求失敗的回調  }).always(function(){    //請求完成的回調  });  //以GET方式請求json數據  Ajax.get('api/demo', {    param1: 'value1',    param2: 'value2'  }).done(function(response){    //請求成功的回調  }).fail(function(){    //請求失敗的回調  }).always(function(){    //請求完成的回調  });  //以POST方式請求json數據  Ajax.post('api/demo', {    param1: 'value1',    param2: 'value2'  }).done(function(response){    //請求成功的回調  }).fail(function(){    //請求失敗的回調  }).always(function(){    //請求完成的回調  });  //以GET方式發送同步請求,獲取json數據  Ajax.syncGet('api/demo', {    param1: 'value1',    param2: 'value2'  }).done(function(response){    //請求成功的回調  }).fail(function(){    //請求失敗的回調  }).always(function(){    //請求完成的回調  });  //以POST方式發送同步請求,獲取json數據  Ajax.syncPost('api/demo', {    param1: 'value1',    param2: 'value2'  }).done(function(response){    //請求成功的回調  }).fail(function(){    //請求失敗的回調  }).always(function(){    //請求完成的回調  });});

由于這個組件的每個實例方法返回的對象就是$.ajax創建的對象,所以我們完全可以照常使用.done .fail .always來添加回調,就跟直接用$.ajax沒有任何區別。為什么API要設計成html, get, post, syncGet, syncPost這幾個方法,而且連dataType基本都是固定的?

那是因為在項目中,我們完全可以約定在異步請求的時候只能用html或json這兩種dataType,其它dataType不允許,現在的web項目這兩種方式已經完全夠用了,至少我沒有碰到過非得使用別的dataType不可的情況;而且在實際工作當中html, get, post, syncGet, syncPost這幾個方法幾乎能夠涵蓋我們需要的所有異步請求的場景,每當我們要用ajax的時候,無非考慮的就是get還是post,同步還是異步,請求的是html還是json這三個問題,通過它們就能把每個問題都解決了。當然jsonp,rest API這兩種情況就另說了,這個組件不是為它們服務的,這也是它的局限性,它還是傾向于在傳統的web項目中使用。

2. ajax緩存代理

要實現一個簡單的ajax緩存代理組件,首先要清楚這個緩存代理的作用,在本文開篇說到過緩存代理的應用場景:當使用緩存代理第一個發起某個請求時,在請求成功后將數據緩存下來,然后當再次發起相同請求時直接返回之前緩存的數據,緩存代理的作用是控制何時發送請求去后臺加載數據,何時不發送請求直接從緩存中讀取之前加載的數據。為了實現一個簡單的緩存代理,有三個問題要解決:

1)代理對象必須與被代理的對象有相同的API 
拿前面的Ajax組件來說,它提供有html, get , post, syncGet, syncPost方法,那么它的代理對象也必須同時具有這些方法,而且調用方式,傳入參數都必須完全一致,只有這樣,當我們在使用代理對象的時候,就跟在使用原組件對象沒有區別。而且在緩存代理內部,在某些條件下是需要調用原組件對象發送ajax請求的,如果接口不同,調用方式不同,參數不同,如何能保證內部能夠正確調用原組件對象呢?這個條件還有一個好處,就是當我們下次不想使用代理對象的時候,能夠以最小的代價將代理對象替換為原組件對象。 
這一點其實是設計模式中代理模式的基本要求。

2)緩存數據存儲時的緩存索引問題 
也就是說我們以什么樣的索引才能保證同一個請求的數據在緩存之后,下次查找時還能根據請求信息查找到呢?ajax緩存有別于其它緩存的地方在于它請求的地址可能包含可變的參數值,同一個地址如果后面的參數不同,那么對應的請求結果也就不一定相同,所以簡單起見,可以考慮把請求地址跟請求參數統一作為緩存索引,這樣就能對緩存進行簡單管理。同時考慮到其它可變性,還應有其它的一些要求,詳見后面組件實現中的注釋說明。

3)緩存有效時間 
雖然要實現的緩存代理很簡單,但是這個問題一定是要考慮的,每個緩存代理實例,能夠緩存數據的有效時間不一定相同,有的可能只緩存幾分鐘,有的可能緩存幾十分鐘,當緩存時間失效時,緩存代理就得刪除原來的緩存,然后重新去加載數據才行。

綜合這些問題,基于第一部分的Ajax組件,最終實現的緩存代理組件AjaxCache的代碼如下(有注釋詳解):

define(function (require, exports, module) {  var $ = require('jquery');  var Ajax = require('mod/ajax');  //緩存列表  var cache = {};  /**   * 生成緩存索引:   * 由于索引是根據url和data生成的(data是一個對象,存放Ajax要提交到后臺的數據)   * 所以要想同一個url,同樣的data能夠有效地使用緩存,   * 切勿在url和data中包含每次可變的參數值,如隨機數等   * 比如有一個請求:   * url: aaa/bbb/cccc?r=0.312738   * data: {name: 'json'}   * 其中url后面的r是一個隨機數,每次外部發起這個請求時,r的值都會變化   * 由于r每次都不同,最終會導致緩存索引不相同,結果緩存就無法命中   * 注:隨機數可放置在原始的Ajax組件內   *   * 還有:如果是同一個接口,最好在同一個頁面內,統一url的路徑類型,要么都是相對路徑,要么都是絕對路徑   * 否則也會導致緩存無法有效管理   */  function generateCacheKey(url, data) {    return url + $.param(data);  }  return function (opts) {    opts = opts || {};    var cacheInterval = opts.cacheInterval || (1000 * 60 * 60);//緩存有效時間,默認60分鐘    var proxy = {};    for (var i in Ajax) {      if (Object.prototype.hasOwnProperty.call(Ajax, i)) {        //在proxy對象上定義Ajax組件每一個實例方法的代理        //注意這個立即調用的函數表達式        //它返回了一個閉包函數就是最終的代理方法        proxy[i] = (function (i) {          return function () {            var _url = arguments[0],              _data = arguments[1],              cacheKey = generateCacheKey(_url, _data),              cacheItem = cache[cacheKey],              isCacheValid = false;            if (cacheItem) {              var curTime = +new Date();              if (curTime - cacheItem.cacheStartTime <= cacheInterval) {                //如果請求時間跟緩存開始時間的間隔在緩存有效時間范圍內,就表示緩存是有效的                isCacheValid = true;              } else {                //否則就把緩存清掉                delete cache[cacheKey];              }            }            if (isCacheValid) {              //模擬一個異步任務來返回已經緩存的數據              //通過$defer延遲對象,可以保證這個模擬任務返回的對象跟原始Ajax組件調用返回的對象有相同的API              //這是代理的關鍵:代理對象與被代理的對象應該具有相同API              //只有這樣當我們取消代理的時候,不會對那些用了代理的組件進行修改              var $defer = $.Deferred();              setTimeout(function () {                $defer.resolve(cacheItem.res);              }, 10);              return $.when($defer);            }            //緩存失效或者沒有緩存的時候調用原始的Ajax組件的同名方法去后臺請求數據            return Ajax[i].apply(Ajax, arguments).done(function (res) {              //在請求成功之后將結果緩存,并記錄當前時間作為緩存的開始時間              cache[cacheKey] = {                res: res,                cacheStartTime: +new Date()              }            });          }        })(i);      }    }    return proxy;  };});

 

在第一部分和本部分的實現中,最關鍵的都是那個立即調用的函數表達式,沒有它返回的閉包,代碼就會有問題,這也是閉包在循環中應用的經典問題。

3. 演示效果

為了說明緩存代理的使用效果,我做了一個演示效果: 
jquery,ajax,二次封裝,AjaxCache 
其中的ajax.js就是第一部分的實現,ajaxCache.js就是第二部分的實現,演示頁面對應代碼中的html/demo.html,相關js是js/app/demo.js:

define(function (require, exports, module) {  var AjaxCache = require('mod/ajaxCache');  //創建代理對象  var Ajax = new AjaxCache({    cacheInterval: 10 * 1000  });  var count = 5;  console.log('時間點:第' + 0 + 's,定時器開始!');  var t = setInterval(function(){    if(count == 0) {      console.log('時間點:第' + (5 - count + 1) * 4 + 's,定時器結束!');      return clearInterval(t);    } else{      console.log('時間點:第' + (5 - count + 1) * 4 + 's:');    }    Ajax.get('../api/data.json', {      name: 'felix'    }).done(function(res){      if(res.code == 200) {        console.log(5 - count + '. data is : ' + JSON.stringify(res.data));      }    });    count --;  },4000);});

 

在這個代碼中,我創建了一個代理對象,能將ajax請求緩存10s,用一個定時器一共調用代理對象五次get方法來發送同一個請求,最終打印效果如下: 
jquery,ajax,二次封裝,AjaxCache 
從結果來看,整個代碼執行了24s,代理發送請求的時間點分別是第4s,第8s,第12s,第16s和第20s。由于代理的緩存有效時間是10s,且第4s是第一次發送請求,所以此時肯定會發送真實的ajax請求;當第8s和第12s的代理發送同一請求時,由于距離緩存的時間只過去了4s和8s,所以緩存還是有效的,這兩個時間點都沒有發送實際的ajax請求;但是當第16s的請求發送時,距離第一次請求的緩存時間已經過去12s,緩存已經失效,所以代理又發送了一次真實的ajax請求,然后緩存被刷新;第20s的請求還是在最新的緩存有效時間內,所以也沒有發送實際的ajax請求。最后在network中可以看到代理發送了5次請求,但是只請求了2次服務,如果把緩存有效時間延長,就能再減少請求后臺的次數,這也是緩存代理對前端性能提升的關鍵。

希望這個演示效果能夠讓你更加清楚地了解緩存代理的作用。

4. 本文總結

本文第1部分總結的實現在我自己的工作中應用很多,至少沒碰到什么問題,不過也有可能是我沒遇到,畢竟那個組件實現還是有不少約束的。第2部分的實現我也是剛剛應用到工作中去,正好有一個功能我考慮到有緩存的必要性,于是就寫了一個較為簡單的實現,雖然簡單,但是已經能解決我的問題了,實際工作本來就是這樣,有些東西沒必要事無巨細的在事前就設計地很完美,先解決問題,然后在遇到新問題的時候再回來重構,有時也是一種更好的工作方法。下一篇博客介紹另外一個用到緩存代理的組件的實現思路,跟省市級聯類似的功能,不過我想的是寫成通用性更強的,能夠與html結構和css盡可能分離的組件,請您繼續關注。

以上這篇對jquery的ajax進行二次封裝以及ajax緩存代理組件:AjaxCache詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持VeVb武林網。



注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩欧美国产激情| 欧美人在线视频| 成人黄色生活片| 日韩精品极品视频免费观看| 中文字幕亚洲一区二区三区五十路| 日韩av片永久免费网站| 久久久天堂国产精品女人| 亚洲精品中文字幕有码专区| 国产日韩视频在线观看| 欧美日本高清视频| 精品国产拍在线观看| 国产脚交av在线一区二区| 国产精品一区二区三区在线播放| 欧美日韩亚洲一区二| 欧美在线欧美在线| 欧美日韩在线免费观看| 亚洲国产精品久久久久秋霞不卡| 欧美插天视频在线播放| 久久精品99无色码中文字幕| 91社影院在线观看| 日韩美女视频中文字幕| 精品露脸国产偷人在视频| 久久人人爽人人爽人人片亚洲| 国产精品久久久久久久久免费| 国产精品美女www| 亚洲精品少妇网址| 奇米4444一区二区三区| 岛国av午夜精品| 揄拍成人国产精品视频| 国产精品自拍小视频| 91po在线观看91精品国产性色| 亚洲国产日韩精品在线| 日韩专区在线播放| 欧美一区三区三区高中清蜜桃| 91精品国产高清自在线| 中文字幕自拍vr一区二区三区| 日韩av男人的天堂| 国产精品偷伦视频免费观看国产| 国产日韩欧美在线播放| 国产精品欧美久久久| 日韩av一区在线观看| 精品亚洲国产成av人片传媒| 成人午夜黄色影院| 91社区国产高清| 国产精品美女网站| 亚洲欧美国产日韩中文字幕| 日韩欧美在线视频免费观看| 欧美色另类天堂2015| 亚洲专区中文字幕| 中文字幕精品www乱入免费视频| 国产香蕉一区二区三区在线视频| 欧美在线视频网| 久久久亚洲福利精品午夜| 日韩有码在线电影| 欧美性猛交xxxx久久久| 亚洲最大福利网| 人体精品一二三区| 日韩av影片在线观看| 午夜精品视频网站| 在线看福利67194| 黄色成人av在线| 欧美在线免费看| 国产精选久久久久久| 国产日韩欧美在线播放| 538国产精品一区二区在线| 国产精品白嫩美女在线观看| 国产91精品黑色丝袜高跟鞋| 日韩精品中文字幕有码专区| 亚洲成人网在线| 影音先锋欧美精品| 91中文在线观看| 岛国视频午夜一区免费在线观看| 欧美孕妇与黑人孕交| 中文字幕亚洲无线码在线一区| 国产精品久久一区主播| 久久久噜久噜久久综合| 久久精品色欧美aⅴ一区二区| 亚洲free性xxxx护士hd| 亚洲香蕉伊综合在人在线视看| 欧美在线精品免播放器视频| 欧美极品在线视频| 欧美日韩亚洲高清| 亚洲精品欧美日韩专区| 日韩成人在线免费观看| 91免费精品视频| 久久久精品国产一区二区| 亚洲在线视频观看| 92看片淫黄大片看国产片| 亚洲人成在线观看网站高清| 丁香五六月婷婷久久激情| 国产精品夜间视频香蕉| 中文字幕久久久av一区| 色综合色综合久久综合频道88| 欧美一性一乱一交一视频| 国产在线拍偷自揄拍精品| 精品爽片免费看久久| 日韩高清有码在线| 国产精品免费小视频| 久久久久久久久久久成人| 国产在线a不卡| 狠狠躁夜夜躁久久躁别揉| 日韩欧美成人精品| 久久久噜噜噜久久中文字免| 成人免费淫片aa视频免费| 国产精品爱久久久久久久| 欧美激情va永久在线播放| 久久精品99久久久香蕉| 日韩免费在线观看视频| 91在线视频九色| 国产精品欧美一区二区三区奶水| 一区二区三区四区在线观看视频| 欧美国产在线电影| 欧美在线性视频| 欧美激情亚洲另类| 91av视频在线观看| 国模极品一区二区三区| 一区国产精品视频| 欧美孕妇毛茸茸xxxx| 日韩黄色在线免费观看| 亚洲欧美日韩图片| 国产精品一区二区久久久久| 欧美成人亚洲成人日韩成人| 国产91在线播放九色快色| 国产精品视频26uuu| 欧美尤物巨大精品爽| 国产男女猛烈无遮挡91| www.欧美视频| 久久精品国产久精国产思思| 一本色道久久综合狠狠躁篇怎么玩| 国产精品热视频| 久久天天躁狠狠躁老女人| 成人免费在线视频网站| 亚洲四色影视在线观看| 国内自拍欧美激情| 国产精国产精品| 美女扒开尿口让男人操亚洲视频网站| 91精品久久久久久久久久另类| 国产91精品久久久| 国产日本欧美一区二区三区在线| 97视频在线观看亚洲| 亚洲欧美日韩精品久久亚洲区| 国产区精品在线观看| 欧美www在线| 亚洲男人7777| 久久久久www| 欧美精品做受xxx性少妇| 亚洲欧美激情视频| 国产精品久久77777| 久久免费精品日本久久中文字幕| 日韩电影免费观看在线| 亚洲欧美日韩第一区| 欧美日韩一区二区精品| 国产91在线播放精品91| 国产欧美精品日韩精品| 欧美插天视频在线播放| 91在线视频导航| 亚洲视频777| 欧美激情按摩在线| 欧美理论片在线观看| 亚洲天堂精品在线| 在线精品国产成人综合| 国产精品久久综合av爱欲tv| 色综合久综合久久综合久鬼88| 57pao国产精品一区|