我如何设计客户端队列系统?

时间:2011-01-12 07:00:31

标签: javascript jquery queue client-side

概览

我正在研究一个项目,我遇到了一个问题,因为事情并没有按照我希望它们发生的顺序发生。所以我一直在考虑设计某种Queue,我可以使用它来组织函数调用和启动期间使用的其他各种JavaScript / jQuery指令,即在页面加载时。我正在寻找的并不一定需要是一个队列数据结构,而是一些系统能够确保事物以我指定的顺序执行,并且只有当前一个任务完成后才能开始新的任务。

我简要地看了jQuery QueueAjaxQueue,但我真的不知道它们是如何工作的,所以我不确定这是否是我想采取的方法......但我会继续阅读有关这些工具的更多信息。

SPECIFICS

目前,我已经进行了设置,以便在$(document).ready(function() {...});内进行一些工作,并在$(window).load(function() {...});内进行其他工作。例如,

<head>
  <script type="text/javascript">    

    // I want this to happen 1st
    $().LoadJavaScript();
    // ... do some basic configuration for the stuff that needs to happen later...

    // I want this to happen 2nd
    $(document).ready(function() {

      // ... do some work that depends on the previous work do have been completed
      var script = document.createElement("script");
      // ... do some more work...
    });

    // I want this to happen 3rd
    $(window).load(function() {

      // ... do some work that depends on the previous work do have been completed
      $().InitializeSymbols();
      $().InitializeBlock();
      // ... other work ... etc...
    });
  </script>
</head>

......这真的很乏味和丑陋,更不用说糟糕的设计了。因此,我想设计一个非常通用的系统,而不是处理那个烂摊子,以便我可以,例如,$().LoadJavaScript();,然后var script = document.createElement("script");,然后$().InitializeSymbols();,然后{{1}然后,队列将执行函数调用和指令,以便在一条指令完成执行后,另一条指令可以启动,直到队列为空而不是我反复调用dequeue。

这背后的原因是,在开始其他工作之前,需要进行一些工作,例如配置和初始化,因为依赖于配置和初始化步骤已经完成。如果这听起来不是一个好的解决方案,请告诉我:))

一些基本工作

我为基本队列which can be found here编写了一些代码,但我希望扩展其功能,以便我可以存储各种类型的“对象”,例如单独的JavaScript / jQuery指令和函数调用,本质上是我想要执行的代码片段。

更新

使用我实现的当前Queue,看起来我可以存储函数并在以后执行它们,例如:

$().InitializeBlock();

我也认为我已经想出了如何存储单个指令,例如// a JS file... $.fn.LoadJavaScript = function() { $.getScript("js/Symbols/Symbol.js"); $.getScript("js/Structures/Structure.js"); }; // another JS file... function init() { // symbols and structures }; // index.html var theQueue = new Queue(); theQueue.enqueue($().LoadJavaScript); theQueue.enqueue(init); var LJS = theQueue.dequeue(); var INIT = theQueue.dequeue(); LJS(); INIT(); 或甚至if-else语句或循环,方法是将它们包装起来:

$('#equation').html("");

但是这种方法需要我等到队列完成它的工作才能继续我的工作。这似乎是一个不正确的设计。有更巧妙的方法吗?另外,我怎么知道某个功能已经完成执行,以便队列可以知道继续前进?是否存在某种我可以等待的返回值或者我可以为队列中的每个任务指定的回调函数?

WRAP-UP

由于我正在做客户端的所有事情而且我不能让Queue独立完成它自己的事情(根据下面的答案),有没有比我等待Queue完成其工作更聪明的解决方案?

由于这更像是一个设计问题,而不是特定的代码问题,我正在寻找解决问题的方法的建议,关于如何设计这个系统的建议,但我绝对欢迎,并希望看到,代码来备份建议:)我也欢迎任何有关我上面链接的Queue.js文件的批评和/或我对我的问题的描述以及我打算采取的解决方法。

谢谢,Hristo

4 个答案:

答案 0 :(得分:2)

我建议使用http://headjs.com/它允许您并行加载js文件,但是按顺序执行它们,基本上与您想要做的事情相同。它非常小,你可以随时用它来获取灵感。

我还要提到依赖执行顺序的处理程序不是好设计。我总是能够将所有引导代码放在ready事件处理程序中。如果您需要访问图像,有些情况下您需要使用加载处理程序,但对我来说这种情况并不常见。

答案 1 :(得分:1)

  

如何在队列中存储代码片段并让它稍后执行

您当前的实施已经适用于此。 JavaScript中没有声明的类型,因此您的队列可以包含任何内容,包括函数对象:

queue.enqueue(myfunc);
var f = queue.dequeue();
f();

  

如何让Queue独立完成自己的事情

JavaScript本质上是单线程的,这意味着只有一件事可以在任何时刻执行。因此,如果这就是您的意思,那么队列就无法“独立”地运行代码的其余部分。

你基本上有两个选择:

  1. 一次一个接一个地运行所有排队的函数 - 这甚至不需要队列,因为它只是简单地将函数调用直接放在代码中。

  2. 使用定时事件:一次运行一个函数,一旦完成,设置超时以在一定时间间隔后执行下一个排队函数。以下是一个例子。


  3. function run() {
      var func = this.dequeue();
      func();
    
      var self = this;
      setTimeout(function() { self.run(); }, 1000);
    }
    

    如果func是异步请求,则必须将setTimeout移至回调函数中。

答案 2 :(得分:1)

这可能有用,这就是你要追求的东西吗?

var q = (function(){
    var queue = [];
    var enqueue = function(fnc){
        if(typeof fnc === "function"){
            queue.push(fnc);
        }
    };

    var executeAll = function(){
        var someVariable = "Inside the Queue";
        while(queue.length>0){
            queue.shift()();
        }
    };

    return {
        enqueue:enqueue,
        executeAll:executeAll 
    };

}());

var someVariable = "Outside!"
q.enqueue(function(){alert("hi");});
q.enqueue(function(){alert(someVariable);});
q.enqueue(function(){alert("bye");});
alert("test");
q.executeAll();

alert("test");在您放入队列之前运行。

答案 3 :(得分:1)

**The main functions**

**From there we can define the main elements required:**

var q=[];//our queue container
var paused=false; // a boolean flag
function queue() {}
function dequeue() {}
function next() {}
function flush() {}
function clear() {}

**you may also want to 'pause' the queue. We will therefore use a boolean flag too. 
Now let's see the implementation, this is going to be very straightforward:**

var q      = [];
var paused = false;

function queue() {
 for(var i=0;i< arguments.length;i++)
     q.push(arguments[i]);
}
function dequeue() {
    if(!empty()) q.pop();
}
function next() {
    if(empty()) return; //check that we have something in the queue
    paused=false; //if we call the next function, set to false the paused
    q.shift()(); // the same as var func = q.shift(); func();
}
function flush () {
    paused=false;
    while(!empty()) next(); //call all stored elements
}
function empty() {  //helper function
    if(q.length==0) return true;
    return false;
}
function clear() {
    q=[];
}

**And here we have our basic queue system!
let's see how we can use it:**

queue(function() { alert(1)},function(){ alert(2)},function(){alert(3)});
next(); // alert 1
dequeue(); // the last function, alerting 3 is removed
flush(); // call everything, here alert 2
clear(); // the queue is already empty in that case but anyway...