큐는 한쪽 끝에서는 삽입 작업만 허용하고 다른 쪽 끝에서는 삭제 작업만 허용하는 선형 목록입니다. 큐는 FIFO(선입선출) 데이터 구조입니다.
큐는 프로그램 설계에서 매우 자주 사용됩니다. JavaScript는 단일 스레드이므로 언제든지 하나의 작업만 실행할 수 있으며 비동기 메커니즘과도 혼합됩니다.
그럼 문제는
1. 비동기 작업을 실행하면 동기 코드가 계속해서 비동기 코드에 의존하게 되어 자연스럽게 오류가 발생하게 됩니다
2. 여러 동기화된 작업이 서로 다른 시간대에 호출됩니다.
jQuery 애니메이션에서는 연속적인 애니메이션 코드를 작성하는 경우가 많습니다
$book.animate({ opacity: 0.25, }).animate({ opacity: 0.5 }).animate({ opacity: 1 })
우리가 느끼는 직관적인 느낌은 첫 번째 애니메이션이 끝난 후 요소의 불투명도가 0.25가 되고 두 번째 애니메이션이 실행되기 시작하면 요소의 불투명도가 0.5가 되는 식입니다. 그런데 사실 여기에는 본질적인 문제가 있습니다. 애니메이션은 비동기적으로 호출되고, animate 메소드는 동기적으로 실행되기 때문에 여기서는 큐를 설계해야 합니다. jQuery는 애니메이션을 위해 특별히 설계된 큐 메소드도 제공합니다
대기열은 또한 특별한 선형 목록입니다. 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>