How would I design a client-side Queue system?

回眸只為那壹抹淺笑 提交于 2021-02-18 10:58:07

问题


OVERVIEW

I'm working on a project and I've come across a bit of a problem in that things aren't happening in the order I want them to happen. So I have been thinking about designing some kind of Queue that I can use to organize function calls and other miscellaneous JavaScript/jQuery instructions used during start-up, i.e., while the page is loading. What I'm looking for doesn't necessarily need to be a Queue data structure but some system that will ensure that things execute in the order I specify and only when the previous task has been completed can the new task begin.

I've briefly looked at the jQuery Queue and the AjaxQueue but I really have no idea how they work yet so I'm not sure if that is the approach I want to take... but I'll keep reading more about these tools.

SPECIFICS

Currently, I have set things up so that some work happens inside $(document).ready(function() {...}); and other work happens inside $(window).load(function() {...});. For example,

<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>

... and this is really tedious and ugly, not to mention bad design. So instead of dealing with that mess, I want to design a pretty versatile system so that I can, for example, enqueue $().LoadJavaScript();, then var script = document.createElement("script");, then $().InitializeSymbols();, then $().InitializeBlock();, etc... and then the Queue would execute the function calls and instructions such that after one instruction is finished executing, the other can start, until the Queue is empty instead of me calling dequeue repeatedly.

The reasoning behind this is that some work needs to happen, like configuration and initialization, before other work can begin because of the dependency on the configuration and initialization steps to have completed. If this doesn't sound like a good solution, please let me know :)

SOME BASIC WORK

I've written some code for a basic Queue, which can be found here, but I'm looking to expand its functionality so that I can store various types of "Objects", such as individual JavaScript/jQuery instructions and function calls, essentially pieces of code that I want to execute.

UPDATE

With the current Queue that I've implemented, it looks like I can store functions and execute them later, for example:

// 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();

I also think I've figured out how to store individual instructions, such as $('#equation').html(""); or perhaps even if-else statements or loops, by wrapping them as such:

theQueue.enqueue(function() { $('#equation').html(""); // other instructions, etc... });

But this approach would require me to wait until the Queue is done with its work before I can continue doing my work. This seems like an incorrect design. Is there a more clever approach to this? Also, how can I know that a certain function has completed executing so that the Queue can know to move on? Is there some kind of return value that I can wait for or a callback function that I can specify to each task in the Queue?

WRAP-UP

Since I'm doing everything client-side and I can't have the Queue do its own thing independently (according to an answer below), is there a more clever solution than me just waiting for the Queue to finish its work?

Since this is more of a design question than a specific code question, I'm looking for suggestions on an approach to solving my problem, advice on how I should design this system, but I definitely welcome, and would love to see, code to back up the suggestions :) I also welcome any criticism regarding the Queue.js file I've linked to above and/or my description of my problem and the approach I'm planning to take to resolve it.

Thanks, Hristo


回答1:


I would suggest using http://headjs.com/ It allows you to load js files in parallel, but execute them sequentially, essentially the same thing you want to do. It's pretty small, and you could always use it for inspiration.

I would also mention that handlers that rely on execution order are not good design. I am always able to place all my bootstrap code in the ready event handler. There are cases where you'd need to use the load handler if you need access to images, but it hasn't been very often for me.




回答2:


Here is something that might work, is this what you're after?

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();

the alert("test"); runs before anything you've put in the queue.




回答3:


how do I store pieces of code in the Queue and have it execute later

Your current implementation already works for that. There are no declared types in JavaScript, so your queue can hold anything, including function objects:

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

how can I have the Queue do its own thing independently

JavaScript is essentially single-threaded, meaning only one thing can execute at any instant of time. So the queue can't really operate "independently" of the rest of your code, if that is what you mean.

You basically have two choices:

  1. Run all the queued functions, one after the other, in a single go -- this doesn't even require a queue since it is the same as simply putting the function calls directly in your code.

  2. Use timed events: run one function at a time and once it completes, set a timeout to execute the next queued function after a certain interval. An example of this follows.


function run() {
  var func = this.dequeue();
  func();

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

If func is an asynchronous request, you'll have to move setTimeout into the callback function.




回答4:


**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...


来源:https://stackoverflow.com/questions/4666130/how-would-i-design-a-client-side-queue-system

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!