For fun, I made a function queue in JavaScript. I named it tinyq. You can add functions to it, and each function is passed the next function in the queue. You can also pass parameters to the functions, and they can return values.
function q(){
var Q = [], t = this;
this.length = 0;
this.add = function (f){
Q.push(f);
this.length++;
};
this.run = function(){
var n = Q.shift();
this.length = Q.length;
if(typeof n === 'function'){
var a = Array.prototype.slice;
return n.apply(window,[function(){
return t.run.apply(t, a.call(arguments));
}].concat(a.call(arguments)));
}
};
}
Here's a simple example of its use.
var Q = new q;
Q.add(function(next, A, B){
return A + ": "+ next(B);
});
Q.add(function(next, C){
return C + "123";
});
console.log(Q.length); // 2
console.log(Q.run("Test", "ABC")); // "Test: ABC123"
So, what do you think of my function queue? Any improvements, or anything I'm doing wrong?
P.S. I was also trying to make this small, any suggestions on making it smaller?
2 Answers 2
I'm not entirely sure where queue semantics are coming into play here. If you just walked up to me and told me you had a function queue for JavaScript, I would expect that I could add a bunch of functions to it, and then it would call them in sequence. But that's not what I'm seeing here.
What I am seeing is a really weirdly formed function composition. Here's how I would do the sample given:
// Create function to show a value with a label.
// Note that it takes a value function, rather than a pure value.
// It also takes any number of arguments for that function, as an array.
var showWithLabel = function (label, valueFunction, valueArguments) {
return (label + ": " + valueFunction.apply(undefined, valueArguments));
};
// Create a function to append "123" onto a string.
var append123 = function (string) {
return (string + "123");
};
// Simple call to execute them together.
showWithLabel("Test", append123, ["ABC"]);
// Actually composite them into a new function.
// This function is the equivalent of the run function.
var composite = function (label, value) {
return showWithLabel(label, append123, [value]);
};
// Now call the composite.
composite("Test", "ABC");
Please comment and discuss here. I want to have a conversation about this, because I feel like there's probably some functionality I'm not understanding about the queue.
-
\$\begingroup\$ This queue can support adding functions and calling them in sequence. Just remove all parameters (except
next
) and it'll work that way. I added the parameter thing for fun. Guess it really doesn't have much real use. This is a neat example, btw. Nice and simple. \$\endgroup\$gen_Eric– gen_Eric2012年01月31日 02:08:51 +00:00Commented Jan 31, 2012 at 2:08 -
1\$\begingroup\$ Oh, I see. You can call
run
multiple times and it will keep reducing the queue down. I must admit that I also don't see much use for that, and I have done a pretty good amount of browser JavaScript coding. Interesting idea though. \$\endgroup\$jdmichal– jdmichal2012年01月31日 02:15:44 +00:00Commented Jan 31, 2012 at 2:15 -
\$\begingroup\$ You can call
run
to run the next item and reduce the queue. Each item is passednext
. Callingnext
will also call the next function and reduce the queue. Bothrun
andnext
can pass parameters to the function in the queue that's being ran. \$\endgroup\$gen_Eric– gen_Eric2012年01月31日 03:27:38 +00:00Commented Jan 31, 2012 at 3:27
I'm still trying to wrap my head around what exactly is happening in that apply
/call
mass :-)
But that may be a hint, that those three lines aren't really well readable. I'm aware you want to keep it small, but unless the code needs to be really, really fast (which I doubt it does) I would prefer readability over shortness.
In that line, I would prefer to have long, more expressive variable names. It be better to use complete words instead of Q
, t
, n
, a
etc.
If in the end, shortness is still important, then use a JavaScript compressor.
BTW, you should keep JavaScript naming conventions in mind, too. Constructor functions ("classes") should be named with capital letters (Q
instead of q
) and fields should use small letters (q
instead of Q
).
Just out of interest: Can you give a concrete use case for this kind of queue?
-
\$\begingroup\$ I really don't have a real use case right now, this is just something I made for fun. I was trying to make a queue like jQuery's
.queue
with more features. Yeah, the.apply
/.call
thing is the heart of this script, and I agree it looks odd. I can try to explain it.a.call(arguments)
turns the arguments "array" into a real array, so I can pass it toapply
.n.apply
calls the next function in the queue, andt.run.apply
is a reference torun
which when called triggers the next function in the queue. \$\endgroup\$gen_Eric– gen_Eric2012年01月13日 14:56:42 +00:00Commented Jan 13, 2012 at 14:56
Queue
implementation a few days ago when answering an SO question. Here is my CR OP: codereview.stackexchange.com/q/28380/3163 ^_^ Have fun with it! \$\endgroup\$