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 相关文章推荐
Tab页界面 用jQuery及Ajax技术实现(php后台)
Oct 12 Javascript
caller和callee的区别介绍及演示结果
Mar 10 Javascript
JS获取并操作iframe中元素的方法
Mar 21 Javascript
Jquery倒数计时按钮setTimeout的实例代码
Jul 04 Javascript
javascript中文本框中输入法切换的问题
Dec 10 Javascript
JQuery radio(单选按钮)操作方法汇总
Apr 15 Javascript
微信小程序 wxapp内容组件 text详细介绍
Oct 31 Javascript
Web安全之XSS攻击与防御小结
Dec 13 Javascript
vue实现鼠标经过动画
Oct 16 Javascript
JS桶排序的简单理解与实现方法示例
Nov 25 Javascript
微信小程序实现滑动翻页效果(完整代码)
Dec 06 Javascript
Javascript柯里化实现原理及作用解析
Oct 22 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
哪吒敖丙传:新人物二哥敖乙出场 小敖丙奶气十足
2020/03/08 国漫
PHP字符转义相关函数小结(php下的转义字符串)
2007/04/12 PHP
php 信息采集程序代码
2009/03/17 PHP
yii框架通过控制台命令创建定时任务示例
2014/04/30 PHP
JS之小练习代码
2008/10/12 Javascript
六款帮助你实现惊艳视差滚动效果的jQuery插件
2012/09/14 Javascript
jQuery实现带渐显效果的人物多级关系图代码
2015/10/16 Javascript
详解JavaScript基于面向对象之继承实例
2015/12/16 Javascript
JS iFrame加载慢怎么解决
2016/05/13 Javascript
利用jsonp跨域调用百度js实现搜索框智能提示
2016/08/24 Javascript
通过vue-router懒加载解决首次加载时资源过多导致的速度缓慢问题
2018/04/08 Javascript
jQuery提示框插件SweetAlert用法分析
2019/08/05 jQuery
微信小程序 button样式设置为图片的方法
2020/06/19 Javascript
[46:58]完美世界DOTA2联赛PWL S3 Forest vs LBZS 第一场 12.17
2020/12/19 DOTA
讲解Python中fileno()方法的使用
2015/05/24 Python
在Django的URLconf中使用多个视图前缀的方法
2015/07/18 Python
Anaconda多环境多版本python配置操作方法
2017/09/12 Python
python 通过logging写入日志到文件和控制台的实例
2018/04/28 Python
在python中实现将一张图片剪切成四份的方法
2018/12/05 Python
Flask之pipenv虚拟环境的实现
2019/11/26 Python
Python3之乱码\xe6\x97\xa0\xe6\xb3\x95处理方式
2020/05/11 Python
python字典的值可以修改吗
2020/06/29 Python
详解tf.device()指定tensorflow运行的GPU或CPU设备实现
2021/02/20 Python
eBay法国购物网站:eBay.fr
2017/10/21 全球购物
英国最大的香水商店:The Fragrance Shop
2018/07/06 全球购物
Moda Italia荷兰:意大利男士服装
2019/08/31 全球购物
什么是SQL Server的确定性函数和不确定性函数
2016/08/04 面试题
人事任命书格式
2014/06/05 职场文书
保护环境的标语
2014/06/09 职场文书
2014年财务科工作总结
2014/11/11 职场文书
大一学生个人总结
2015/02/15 职场文书
党员承诺书格式范文
2015/04/28 职场文书
2015年共青团工作总结
2015/05/15 职场文书
将Python代码打包成.exe可执行文件的完整步骤
2021/05/12 Python
java如何实现socket连接方法封装
2021/09/25 Java/Android
利用正则表达式匹配浮点型数据
2022/05/30 Java/Android