JavaScript中数据结构与算法(二):队列


Posted in Javascript onJune 19, 2015

队列是只允许在一端进行插入操作,另一个进行删除操作的线性表,队列是一种先进先出(First-In-First-Out,FIFO)的数据结构

队列在程序程序设计中用的非常的频繁,因为javascript单线程,所以导致了任何一个时间段只能执行一个任务,而且还参杂了异步的机制,

那么带来的问题:

1. 在异步操作执行的时候,同步代码还在继续,那么同步代码依赖异步,自然就会出错

2. 多个同步的任务在不同的时间段被调用

jQuery的动画中,我们经常写一段连续的动画代码

$book.animate({
  opacity: 0.25,
}).animate({
  opacity: 0.5
}).animate({
  opacity: 1
})

 

给我们的直观感觉就是:第一个animate结束后元素的opacity变成0.25,然后开始继续执行第二个animate,元素的opacity变成0.5, 之后类推。但是实际上来说这里就设计了一个本质的问题,动画可是异步调用的,animate方法是同步在执行的,所以这里就需要设计到队列,jQuery也给出了一个专门为动画设计的queue方法

队列本来也是一种特殊的线性表,在JavaScript我们可以直接使用数组实现这样的一个设计,数组的push()方法可以在数组末尾加入元素,shift()方法则可删除数组的第一个元素。

function Queue() {
  this.dataStore = [];
  this.enqueue  = enqueue;
  this.dequeue  = dequeue;
  this.first   = first;
  this.end    = end;
  this.toString = toString;
  this.empty   = empty;
}

///////////////////////////
// enqueue()方法向队尾添加一个元素: //
///////////////////////////
function enqueue(element) {
  this.dataStore.push(element);
}

/////////////////////////
// dequeue()方法删除队首的元素: //
/////////////////////////
function dequeue() {
  return this.dataStore.shift();
}

/////////////////////////
// 可以使用如下方法读取队首和队尾的元素: //
/////////////////////////
function first() {
  return this.dataStore[0];
}

function end() {
  return this.dataStore[this.dataStore.length - 1];
}

/////////////////////////////
// toString()方法显示队列内的所有元素 //
/////////////////////////////
function toString() {
  var retStr = "";
  for (var i = 0; i < this.dataStore.length; ++i) {
    retStr += this.dataStore[i] + "\n";
  }
  return retStr;
}

////////////////////////
// 需要一个方法判断队列是否为空 //
////////////////////////
function empty() {
  if (this.dataStore.length == 0) {
    return true;
  } else {
    return false;
  }
}

var q = new Queue();
q.enqueue("Aaron1");
q.enqueue("Aaron2");
q.enqueue("Aaron3");

console.log("队列头: " + q.first());  //("Aaron1");
console.log("队列尾: " + q.end()); //("Aaron3");

 

队列采用的是线性的存储,那么就存在着顺序储存的一些弊端,比如排队买票,如果第一个买好了,后面的就会自然的往前移动一个空位,这样涉及到整个队列的每一个成员都要往前移动,不过JavaScript的队列是用数组描述的,底层解决了些弊端了。当然还有查找算法上的问题,比如可以用数组实现单链表结构等等,我们这里只讨论javascript的队列

模拟jQuery,使用队列实现一个动画

<div id="div1" style="width:100px;height:50px;background:red;cursor:pointer;color:#fff;text-align:center;line-height:50px;">点击</div>

(function($) {

  window.$ = $;

})(function() {

  var rquickExpr = /^(?:#([\w-]*))$/;

  function aQuery(selector) {
    return new aQuery.fn.init(selector);
  }

  /**
   * 动画
   * @return {[type]} [description]
   */
  var animation = function() {
    var self = {};
    var Queue = []; //动画队列
    var fireing = false //动画锁
    var first = true; //通过add接口触发

    var getStyle = function(obj, attr) {
      return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, false)[attr];
    }

    var makeAnim = function(element, options, func) {
      var width = options.width
        //包装了具体的执行算法
        //css3
        //setTimeout
      element.style.webkitTransitionDuration = '2000ms';
      element.style.webkitTransform = 'translate3d(' + width + 'px,0,0)';

      //监听动画完结
      element.addEventListener('webkitTransitionEnd', function() {
        func()
      });
    }

    var _fire = function() {
      //加入动画正在触发
      if (!fireing) {
        var onceRun = Queue.shift();
        if (onceRun) {
          fireing = true;
          //next
          onceRun(function() {
            fireing = false;
            _fire();
          });
        } else {
          fireing = true;
        }
      }
    }

    return self = {
      //增加队列
      add: function(element, options) {
        Queue.push(function(func) {
          makeAnim(element, options, func);
        });

        //如果有一个队列立刻触发动画
        if (first && Queue.length) {
          first = false;
          self.fire();
        }
      },
      //触发
      fire: function() {
        _fire();
      }
    }
  }();


  aQuery.fn = aQuery.prototype = {
    run: function(options) {
      animation.add(this.element, options);
      return this;
    }
  }

  var init = aQuery.fn.init = function(selector) {
    var match = rquickExpr.exec(selector);
    var element = document.getElementById(match[1])
    this.element = element;
    return this;
  }

  init.prototype = aQuery.fn;

  return aQuery;
}());

//dom
var oDiv = document.getElementById('div1');

//调用
oDiv.onclick = function() {
  $('#div1').run({
    'width': '500'
  }).run({
    'width': '300'
  }).run({
    'width': '1000'
  });
};

测试

<!doctype html><div id="div1" style="width:100px;height:50px;background:red;cursor:pointer;color:#fff;text-align:center;line-height:50px;" data-mce-style="width: 100px; height: 50px; background: red; cursor: pointer; color: #fff; text-align: center; line-height: 50px;">点击</div><script type="text/javascript">
 
(function($) {

 window.$ = $;

})(function() {

 var rquickExpr = /^(?:#([\w-]*))$/;

 function aQuery(selector) {
 return new aQuery.fn.init(selector);
 }

 /**
 * 动画
 * @return {[type]} [description]
 */
 var animation = function() {
 var self = {};
 var Queue = []; //动画队列
 var fireing = false //动画锁
 var first = true; //通过add接口触发

 var getStyle = function(obj, attr) {
  return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, false)[attr];
 }

 var makeAnim = function(element, options, func) {
  var width = options.width
  //包装了具体的执行算法
  //css3
  //setTimeout
  element.style.webkitTransitionDuration = '2000ms';
  element.style.webkitTransform = 'translate3d(' + width + 'px,0,0)';

  //监听动画完结
  element.addEventListener('webkitTransitionEnd', function() {
  func()
  });
 }

 var _fire = function() {
  //加入动画正在触发
  if (!fireing) {
  var onceRun = Queue.shift();
  if (onceRun) {
   fireing = true;
   //next
   onceRun(function() {
   fireing = false;
   _fire();
   });
  } else {
   fireing = true;
  }
  }
 }

 return self = {
  //增加队列
  add: function(element, options) {
  Queue.push(function(func) {
   makeAnim(element, options, func);
  });

  //如果有一个队列立刻触发动画
  if (first && Queue.length) {
   first = false;
   self.fire();
  }
  },
  //触发
  fire: function() {
  _fire();
  }
 }
 }();


 aQuery.fn = aQuery.prototype = {
 run: function(options) {
  animation.add(this.element, options);
  return this;
 }
 }

 var init = aQuery.fn.init = function(selector) {
 var match = rquickExpr.exec(selector);
 var element = document.getElementById(match[1])
 this.element = element;
 return this;
 }

 init.prototype = aQuery.fn;

 return aQuery;
}());


//dom
var oDiv = document.getElementById('div1');

//调用
oDiv.onclick = function() {
  $('#div1').run({
    'width': '500'
  }).run({
    'width': '300'
  }).run({
    'width': '1000'
  });
};

</script>
Javascript 相关文章推荐
基于jquery实现后台左侧菜单点击上下滑动显示
Apr 11 Javascript
js跨浏览器实现将字符串转化为xml对象的方法
Sep 25 Javascript
jquery实现倒计时代码分享
Jun 13 Javascript
jquery解决客户端跨域访问问题
Jan 06 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成&quot;...&quot;)
Nov 28 Javascript
hovertree插件实现二级树形菜单(简单实用)
Dec 28 Javascript
JS获取字符对应的ASCII码实例
Sep 10 Javascript
Vue创建头部组件示例代码详解
Oct 23 Javascript
nuxt中使用路由守卫的方法步骤
Jan 27 Javascript
解决在layer.open中使用时间控件laydate失败的问题
Sep 11 Javascript
js基础之事件捕获与冒泡原理
Oct 09 Javascript
vue 实现移动端键盘搜索事件监听
Nov 06 Javascript
JavaScript中数据结构与算法(一):栈
Jun 19 #Javascript
JQuery中模拟image的ajaxPrefilter与ajaxTransport处理
Jun 19 #Javascript
c#程序员对TypeScript的认识过程
Jun 19 #Javascript
JavaScript和JQuery的鼠标mouse事件冒泡处理
Jun 19 #Javascript
TypeScript 中接口详解
Jun 19 #Javascript
TypeScript 学习笔记之基本类型
Jun 19 #Javascript
使用Chrome浏览器调试AngularJS应用的方法
Jun 18 #Javascript
You might like
从零开始 教你如何搭建Discuz!4.1论坛
2006/07/07 PHP
php 伪造HTTP_REFERER页面URL来源的三种方法
2016/09/22 PHP
js调试工具 Javascript Debug Toolkit 2.0.0版本发布
2008/12/02 Javascript
jsTree树控件(基于jQuery, 超强悍)[推荐]
2009/09/01 Javascript
JavaScript快速检测浏览器对CSS3特性的支持情况
2012/09/26 Javascript
JS获得QQ号码的昵称,头像,生日的简单实例
2013/12/04 Javascript
JavaScript中的this机制
2016/01/30 Javascript
jQuery过滤选择器经典应用
2016/08/18 Javascript
jQuery 特性操作详解及实例代码
2016/09/29 Javascript
jQuery 禁止表单用户名、密码自动填充功能
2017/10/30 jQuery
Mint UI 基于 Vue.js 移动端组件库
2017/11/07 Javascript
Vue props用法详解(小结)
2018/07/03 Javascript
vue自定义tap指令及tap事件的实现
2018/09/18 Javascript
Layui实现数据表格默认全部显示(不要分页)
2019/10/26 Javascript
在vue中阻止浏览器后退的实例
2019/11/06 Javascript
用于统计项目中代码总行数的Python脚本分享
2015/04/21 Python
Python用字典构建多级菜单功能
2019/07/11 Python
在flask中使用python-dotenv+flask-cli自定义命令(推荐)
2020/01/05 Python
利用CSS3实现开门效果实例源码
2016/08/22 HTML / CSS
CSS3 border-radius圆角的实现方法及用法详解
2020/09/14 HTML / CSS
HTML5重塑Web世界它将如何改变互联网
2012/12/17 HTML / CSS
澳大利亚买卖正宗二手奢侈品交易平台:Luxe.It.Fwd
2019/10/16 全球购物
Blue Nile中国官网:全球知名的钻石和珠宝网络零售商
2020/03/22 全球购物
自我评价的正确写法
2013/09/19 职场文书
仓管员岗位职责范文
2013/11/08 职场文书
物流专业毕业生推荐信范文
2013/11/18 职场文书
行政专员工作职责
2013/12/22 职场文书
创业计划书六个要素
2013/12/26 职场文书
特色蛋糕店创业计划书
2014/01/28 职场文书
人民调解员先进事迹材料
2014/05/08 职场文书
2015年财政局工作总结
2015/05/21 职场文书
薪资证明范本
2015/06/19 职场文书
2016年学校禁毒宣传活动工作总结
2016/04/05 职场文书
如何利用JavaScript实现二叉搜索树
2021/04/02 Javascript
python 办公自动化——基于pyqt5和openpyxl统计符合要求的名单
2021/05/25 Python
Python利用FlashText算法实现替换字符串
2022/03/31 Python