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.mzph.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…