JavaScript --- 自定義優先級隊列

根據HTTP1.1的規范,一個客戶端在同一時刻與同一域名不能有兩個以上的連接。為了完全符合HTTP1.1,一個典型的解決方案就是使用優先級隊列.下面是自定義的優先級隊列

/**
* 用原型模式定義PriorityQueue的方法,
* 如果沒有定義_compare()方法,那么第一個方法就是默認的_compare()方法.
* 由于方法并不是作為公有屬性訪問的,因此實現一個prioritize()來使用該方法
*/ PriorityQueue.prototype = {// _compare()方法只是最基本的比較函數,它基于每個項的原始值來確定哪個項應該排在前面._compare : function (oValue1, oValue2) {if (oValue1 < oValue2) {return -1;} else if (oValue1 > oValue2) {return 1;} else {return 0;}},// 當把新項添加到隊列中時,將調用prioritize()方法來保證這些項按正確的順序排列。對于prioritize : function () {this._items.sort(this._compare);},// 對于優先級隊列而言,有5個方法來完成其基本操作:get()、item()、peek()、put()和size()// get()方法用來返回隊列中指定位置的項get : function() {return this._items.shift();},// item()方法用來返回隊列中指定位置的項。item : function (iPos) {return this._items[iPos];},// peek()方法用來獲取隊列中的下一個項,但不從隊列中刪除(只是查看下一項的值)peek : function () {return this._items[0];}// put()方法負責將新的值添加到隊列中put : function (oValue) {this._items.push(oValue);this.prioritize();},// size()方法將返回隊列中項的總數size : function () {return this._items.length;}// PriorityQueue對象的最后一個方法是remove(),它將再隊列中搜素指定的值,然后將其刪除.remove : function (oValue) {for (var i=0; i < this._items.length; i++) {if (this._items[i] === oValue) {this._items.splice(i, 1);return true;}}return false;
};

上面我們自定義了一個優先級隊列函數PriorityQueue ,它的作用是對XHR請求按照優先級進行排序(若傳入了排序的規則,則按排序的規則,否則按照默認的規則)

有了PriorityQueue之后,下面還需要了解一下請求描述對象(了解一下每個字段什么意思)

var oRequest = {priority: 1, // 優先級type: "post", // 請求方式url:  ,  // 請求路徑data: "post_data",oncancel: function () {}, // 取消執行的函數onsuccess: function () {}, // 成功執行的函數onnotmodified: function () {}, // 服務器端請求數據未更新執行的函數onfailure: function () {}, // 請求失敗執行的函數scope: Object  // 該函數調用的作用域,默認是全局 

在了解了請求描述對象之后,下面可以開始對請求進行排隊了

var RequestManager = (function () {var oManager = {AGE_LIMIT : 60* 1000 ,   // 最大等待時間.DEFAULT_PRIORITY: 10,  // 默認優先級_active: new Array(), // 后面會用到,// _pending()方法:用于比較的函數// oRequest1和oRequest2是XHR的**請求描述對象**_pending : new PriorityQueue(function (oRequest1, oRequest2) {return oRequest1.priority - pRequest2.priority;}),// 上面已經自定義了優先級隊列PriorityQueue,并且將XHR請求按照優先級排進了PriorityQueue中,接下來是發送請求.// 在發送請求之前,我們需要兼容的創建XHR方法_createTransport : function () {if (typeof XMLHttpRequest != "undefined") {return new XMLHttpRequest();} else if (typeof ActiveXObject ! = "undefined") {var oHttp = null;try {oHttp = new ActiveXObject("MSXML2.XmlHttp.6.0");return oHttp;} catch (oEx) {try {pHttp = new ActiveXObject("MSXML2.XmlHttp.3.0");return oHttp;} catch (oEx2) {throw Error ("Cannot create XMLHttp object.");}}}},// 上面方法已經可以創建合適的XHR對象了,下面該發送請求了_sendNext : function () {if (this._active.length < 2) {var oRequest = this._pending.get();if (oRequest != null) {this._active.push(oRequest);oRequest.transport = this._createTransport();oRequest.transport.open(oRequest.type, oRequest.url, true);oRequest.transport.send(oRequest.data);oRequest.active = true;}}},/***監控請求,檢查每個活動請求的狀態*/ _checkActiveRerquests : function () {var oRequest = null;var oTransport = null;// 使用一個for循環來遍歷active數組中的每個請求,(由于請求可能被刪除,因此這個循環以反向順序來檢查避免遺漏某個請求)for (var i=this._active.length-1; i >=0; i--) {oRequest = this._active[i]; // 保留每個請求oTransport =oRequest.transport;if (oTransport.readyState == 4) {  // 檢查,若狀態為4則進一步檢查oRequest.active = false;  // 將active屬性置為false,說明該請求已經被返回并已完成this._active.splice(i, 1);var fnCallback = null;if (oTransport.status >= 200 && oTransport.status < 300) {  // 狀態碼在200~299之間,變量fnCallback將被賦值為onsuccessif (typeof oRequest.onsuccess == "function") {fnCallback = oRequest.onsuceess;}} else if (oTransport.status == 304) {  // 狀態碼為304,fnCallback被賦值為onnotmodifiedif (typeof oRequest.onnotmodified == "function") {fnCallback = oRequest.onnotmodified;}} else {if (typeof oRequest.onfailure == "function") {   // 其他狀態碼,fnCallback賦值為onfailurefnCallback = oRequest.onfailure;}}// 檢查fnCallback函數是否為一個有效函數,若有效則設置一個延遲函數去執行它,設置延遲可以確保輪詢數能在回調函數執行前執行完畢.if (fnCallback != null) { /*** 為了確保在正確的作用域內執行,將在需要的時候實時創建一個傳給setTimeout()函數的函數.* 這個匿名函數有3個參數,以便為每個變量創建正確的副本*/setTimeout((function (fnCallback, oRequest, oTransport) {return function () {fnCallback.call(oRequest.scope ||window, {status: oTransport.status,data: oTransport.responseText,request: oRequest});}}) (fnCallback, oRequest, oTransport), 1);}}}},// 上面的優先級策略存在一個風險,優先級低的有可能永遠不會執行// 解決辦法是,設置一個固定的時間,將隊列中的請求描述對象的優先級提升一級_agePromote : function() {for (var i=0; i < this._pending.size(); i++) {var oRequest = this._pending.item(i);oRequest.age += this.INTERVAL;if (oRequest.age >= this.AGE_LIMIT) {oRequest.age =0;oRequset.priority--;}}this._pending.prioritize();},// 在請求被執行之前,有可能需要取消它。通過cancel()方法,可以從請求隊列中刪除請求描述對象cancel : function (oRequest) {if (!this._pending.remove(oRequest)) {oRequest.transport.abort();if (this._active[0] === oRequest) {this._active.shift();} else if (this._active[1] === oRequest) {this._active.pop();}if (typeof oRequest.oncancel == "function") {oRequest.oncancel.call(oRequest.scope || window,{request : oRequest});}},// 針對定期刷新模式,定義其優先級為3poll : function (oRequest) {oRequest.priority = 3;this.send(oRequest);},// 針對預先獲取和多階段下載模式prefetch : function (oRequest) {oRequest.priority = 5;this.send(oRequest);}// send()是將請求添加到隊列中的公有方法// 首先檢查是否是有效的優先級,如果不是則使用默認的優先級(10,最低).send : function (oRequest) {if(typeof oRequest.priority != "number"){oRequest.priority = this.DEFAULT_PRIORITY;}oRequest.active = false;  // 用來確定當前請求是否在執行oRequest.age = 0;this._pending.put(oRequest);},// 針對用戶操作,優先級最高submit : function (oRequest) {oRequest.priority = 0;this.send(oRequest);},// 針對提交節流模式 ,優先級比較高為2submitPart : function (oRequest) {oRequest.priority = 2;this.send(oRequest);}
};// 啟動
setInterval (function () {RequestManager._checkActiveRequests();RequestManager._sendNext();RequestManager._agePromote();
}, oManager.INTERVAL);//返回該對象return oManager;
}) ();
// 使用上面定義的方法
RequestManager.poll({type: "get",url: "example.html",data: ""post_data",onsuccess: function() {},
});RequestManager.submitPart({type:"post",url: "handler.html",data: "name=Nicholas",onsuccess: function() {},
});

參考《Ajax高級程序設計》(第二版) P110~P126

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251540.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251540.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251540.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

可添加至收藏夾并在瀏覽器地址欄運行的JS代碼

編輯當前網頁 代碼如下&#xff1a; javascript:document.body.contentEditabletrue; document.designModeon; void 0 無敵圖片風火輪 在地址欄運行下面的代碼可提取所有圖片元素在頁面上滾動顯示&#xff0c;屬于網頁顯示特效。 代碼如下&#xff1a; javascript:R0; x1.1; y1…

SOA相關資料

http://www.cnblogs.com/mushroom/p/4369032.html轉載于:https://www.cnblogs.com/tianciliangen/p/7825959.html

打造自己Django博客日記

本教程使用的開發環境 本教程寫作時開發環境的系統平臺為 Windows 10 &#xff08;64 位&#xff09;&#xff0c;Python 版本為 3.5.2 &#xff08;64 位&#xff09;&#xff0c;Django 版本為 1.10.6。 建議盡可能地與教程的開發環境保持一致&#xff08;尤其是 Python 與 D…

vue --- 使用字符串'api'跨域請求資源

vue環境下,修改config/index.js文件 module.exports {data: {proxyTable: {/api: {target: http://siwei.me, // 將api轉發到siwei.me上changeOrigin: true,pathRewrite: {^/api: // 去掉url中的api}}}, }原請求: http://localhost:8080/api/interface/blogs/all 新請…

重慶兩江新區將建國內最大“云計算”數據基地

全市經濟工作會指出&#xff0c;要盡快啟動、全力爭取打造國內最大的數據處理基地&#xff0c;最終要做成上百萬臺服務器、上千億美元規模的“云計算”基地&#xff0c;成為全球數據開發和處理中心。昨日&#xff0c;市經信委主任沐華平接受本報專訪時表示&#xff0c;重慶正在…

如何在前端生成二維碼

第一步&#xff1a; 引入&#xff1a;<script src"qrcode.js"></script> 第二步&#xff1a; <div id"qrcode"></div> 第三步&#xff1a; // 1.簡單使用方式 &#xff1a;new QRCode(document.getElementById(qrcode), http://ww…

vue --- Vue中的路由跳轉問題

import Vue from vue import Router from vue-router // 前2個導入時vue框架自帶的 import SayHi from /components/SayHi // 這個導入是自己寫的位于components下的sayHiVue.use(Router) // 用到了vue的Router模塊 export default new Router({routes: [{path: /say_hi,…

水瓶與天蝎的八年愛戀(圖

新浪網友&#xff1a;kinkihi 水瓶與天蝎的八年愛戀我水瓶&#xff0c;他蝎子。我們相戀8年&#xff0c;確切的說中間有5年在一起的時間不超過6個月&#xff0c;兩人一直處于異地狀態&#xff0c;說出來可能沒幾個人能信&#xff0c;我們是這樣走過來的。我一直是嚴格要求自己&…

Controller上使用@CrossOrigin注解

本文首次發布于My Blog,作者Ian,轉載請保留原文鏈接。 就是一個跨域的注解 Spring MVC 從4.2版本開始增加了對CORS的支持 CORS介紹請看這里&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS 參考isea533&#xff1a;https://blog.csdn.net/…

vue --- 基本的表單元素

<template> <div>input: <input typetext v-modelinput_value />,輸入的值: {{input_value}}<hr />text area: <textarea v-model"textarea_value"></textarea>,輸入的值: {{textarea_value}}<hr/>radio:<input typera…

相關名詞淺析

分布式&#xff1a;一個業務分拆多個子業務&#xff0c;部署在不同的服務器上集群&#xff1a;同一個業務&#xff0c;部署在多個服務器上轉載于:https://www.cnblogs.com/yuki-l/p/9202819.html

Beta 討論分析——持續更新ing

wonderland Beta 討論分析 標簽&#xff08;空格分隔&#xff09;&#xff1a; 軟工實踐 wonderland 主要工作: info信息&#xff1a; 1、關聯賬號界面:hbb 2、標簽檢索界面:hbb 3、近期活躍度(cf、hdu):橘子 4、增加個人頭像 wiki &#xff1a; 點贊排行、閱讀量排行返回數據 …

vue --- 提交表單到服務器

<template> <div><textarea v-modelcontent></textarea><br/><input typebutton clicksubmit value留言 /> </div> </template><script> export default {data () {return {content: }},methods: {submit: function () …

節約內存:Instagram的Redis實踐(轉)

一、問題&#xff1a; 數據庫表數據量極大&#xff08;千萬條&#xff09;&#xff0c;要求讓服務器更加快速地響應用戶的需求。二、解決方案&#xff1a;1.通過高速服務器Cache緩存數據庫數據2.內存數據庫三、主流解Cache和數據庫對比&#xff1a;從以上各數據可知&#xff0c…

多數公司容易犯的5個大數據錯誤

多數公司容易犯的5個大數據錯誤 如今&#xff0c;大數據革命驅動了現代工業發展&#xff0c;每天都有越來越多的企業采用大數據技術。然而&#xff0c;盡管大量數據已經存在和應用了很長時間&#xff0c;但如何使用它&#xff0c;仍然存在許多嚴重的錯誤。 以下是企業容易犯的5…

vue --- SPA模式的組件

SPA&#xff1a;單頁應用(Single Page App),具體好處,百度搜索 我們可以想象一個場景&#xff0c;有兩個頁面,每個頁面的頭部都有一張 Logo 圖片.如果每次都寫成原始 HTML 的話,代碼就會重復. // 頁面1的代碼如下:<div classlogo><img srcurl> </div>// 頁面…

(2.15)備份與還原--使用作業備份、清理過期備份、清理歷史記錄、事務日志是否備份過...

一、建立作業備份數據庫 打開SQL SERVER MANAGEMENT STUDIO&#xff0c;啟動SQL SERVER代理服務&#xff08;注意在“控制面板-管理工具-服務”中設置SQL SERVER AGENT的啟動類型為自動&#xff09;。啟動后點擊“作業-新建作業”&#xff0c;彈出一個作業屬性的窗口&#xff0…

javascript+HTML+CSS面試題

今天參加面試&#xff0c;考了我三個小時&#xff0c;考暈了&#xff0c;趕緊補習補習javascript的知識&#xff01;&#xff08;另&#xff1a;人事部明明說招HTML5CSS3jQuery&#xff0c;考1個半小時左右&#xff0c;怎么變成了考傳統DIVCSSjavascript啦&#xff0c;嗚嗚嗚~~…

android 對話框

android 8種對話框&#xff08;Dialog&#xff09;使用方法匯總 作者&#xff1a;gzdaijie本文為作者原創&#xff0c;轉載請注明出處&#xff1a;https://www.cnblogs.com/gzdaijie/p/5222191.html 目錄 1.寫在前面2.代碼示例2.1 普通Dialog&#xff08;圖1與圖2&#xff09;2…

Java 多線程 之 suspend掛起 線程實例

http://www.verejava.com/?id16992945731073 package com.suspend.resume; /*題目: 人們在火車站的售票窗口排隊買火車票1. 北京西站開門2. 打開售票窗口3. 北京西站有10張去長沙的票4. 打開2個售票窗口, 5 假設每個售票窗口每隔1秒鐘買完一張票1. 根據 名詞 找類人們(Person…