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 相关文章推荐
javascript 获取表单file全路径
Dec 31 Javascript
jquery插件 autoComboBox 下拉框
Dec 22 Javascript
使用jquery实现图文切换效果另加特效
Jan 20 Javascript
瀑布流布局并自动加载实现代码
Mar 12 Javascript
浏览器图片选择预览、旋转、批量上传的JS代码实现
Dec 04 Javascript
js如何获取兄弟、父类等节点
Jan 06 Javascript
让IE8浏览器支持function.bind()方法
Oct 16 Javascript
React Native 环境搭建的教程
Aug 19 Javascript
JavaScript轮播停留效果的实现思路
May 24 Javascript
手动下载Chrome并解决puppeteer无法使用问题
Nov 12 Javascript
elementUI select组件默认选中效果实现的方法
Mar 25 Javascript
JS函数式编程实现XDM一
Jun 16 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
《逃离塔科夫》——“萌新劝退,老手自嗨”的硬核FPS游戏
2020/04/03 其他游戏
一个oracle+PHP的查询的例子
2006/10/09 PHP
PHP中GET变量的使用
2006/10/09 PHP
php xfocus防注入资料
2008/04/27 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
php简单处理XML数据的方法示例
2017/05/19 PHP
ASP.NET jQuery 实例7 通过jQuery来获取DropDownList的Text/Value属性值
2012/02/03 Javascript
JavaScript 语言基础知识点总结(思维导图)
2013/11/10 Javascript
解决js中window.open弹出的是上次的缓存页面问题
2013/12/29 Javascript
将HTML格式的String转化为HTMLElement的实现方法
2014/08/07 Javascript
js实现背景图片感应鼠标变化的方法
2015/02/28 Javascript
JS获取鼠标选中的文字
2016/08/10 Javascript
jquery表单插件form使用方法详解
2017/01/20 Javascript
JavaScript canvas实现围绕旋转动画
2017/11/18 Javascript
koa2实现登录注册功能的示例代码
2018/12/03 Javascript
微信小程序自定义键盘 内部虚拟支付
2018/12/20 Javascript
详解vue配置后台接口方式
2019/03/29 Javascript
JS中的防抖与节流及作用详解
2019/04/01 Javascript
详解vue为什么要求组件模板只能有一个根元素
2019/07/22 Javascript
javascript面向对象三大特征之多态实例详解
2019/07/24 Javascript
解决vue项目刷新后,导航菜单高亮显示的位置不对问题
2019/11/01 Javascript
Python中的异常处理简明介绍
2015/04/13 Python
关于Python正则表达式 findall函数问题详解
2018/03/22 Python
Python 绘图库 Matplotlib 入门教程
2018/04/19 Python
Python根据已知邻接矩阵绘制无向图操作示例
2018/06/23 Python
Python使用爬虫抓取美女图片并保存到本地的方法【测试可用】
2018/08/30 Python
python+rsync精确同步指定格式文件
2019/08/29 Python
Python3.8.2安装包及安装教程图文详解(附安装包)
2020/11/28 Python
SmartBuyGlasses中国:唯视良品(销售名牌太阳镜、墨镜和眼镜框)
2017/07/03 全球购物
捷克原创男装和女装购物网站:Bolf.cz
2018/04/28 全球购物
汉米尔顿手表官网:Hamilton
2020/09/13 全球购物
工厂保洁员岗位职责
2013/12/04 职场文书
节能环保家庭事迹材料
2014/08/27 职场文书
MySQL 视图(View)原理解析
2021/05/19 MySQL
Mysql数据库索引面试题(程序员基础技能)
2021/05/31 MySQL
分享3个非常实用的 Python 模块
2022/03/03 Python