My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Friday, March 09, 2012

A Tweet Sized Queue System

The Code

This is the 138 bytes version:

function Queue(args, f) {
setTimeout(args.next = function next() {
return (f = args.shift()) ? !!f(args) || !0 : !1;
}, 0);
return args;
}

While this is the 96 one:

function Queue(a,b){setTimeout(a.next=function(){return(b=a.shift())?!!b(a)||!0:!1},0);return a}


The Why

In almost every QCon London talk I have heard the word asynchronous. Well, the aim of the tweet sized function I have just written above is to make things easier.
After I have implemented builder/JSBuilder.js for wru, so that Python is not needed anymore to build the tiny library, I needed to make builder/build.js usable in a way that asynchronous calls through node won't bother, at least visually, the normal flow of the script.
After that I have thought: "why not making a generic Queue function with Promises like approach" ?

The What

It's quite straight forward, you create a queue, you use the queue. You might eventually pollute the queue or change its order, since the queue is nothing different from a generic Array with an extra method on it: next().
Here a basic example:

Queue([
function (queue) {
// do amazing stuff asynchronously
setTimeout(function () {
queue.message = "Hello Queue";
queue.next();
}, 500);
},
function (queue) {
// do something else
alert(queue.message);
// Hello Queue
queue.next(); // not necessary at the end
// does not hurt thought
}
]);


That's Pretty Much It

So, the queue argument is the array created initially to define the ordered list of function.
This means you can recycle this variable even adding custom properties but most important is that you can change the queue via Array.prototype.splice/unshift/pop/push() methods and decide the future or the next function to execute runtime, if needed.
The only extra bit is about returning true or false in case there was a next() to execute or not.

Last, but not least, of course you can create new Queue([]) inside queues ... so, this is actually more powerful than many other queue systems I have seen so far and ... hey, 96 bytes: enjoy!

5 comments:

alexkunin said...

Nice bit of code! But are you sure you need that setTimeout inside Queue? Its effect is so subtle, that it is hard (for me) to imaging a situation where user could feel the difference. And minimified version in this case will be 89b only.

Also, I'd prefer a little more verbose version: http://jsfiddle.net/XT4uF/5/

Andrea Giammarchi said...

the setTimeout is there to be able to:
1. start the async queue without any extra action
2. being able to address the queue object and use it inside callbacks

var q = Queue(arrayOfQueue);

where each function can use q.next() directly.
The queue object is sent in any case as argument but with a private list of functions inside a closure I thought that could be handy.

The point is that you don't really need a library to organize things, the logic can be so simple that it fits indeed in a tweet.

Feel free to use your own version, change or improve it, don't waste your time with external 3rd parts libraries that do a lot of unnecessary magic, imho ;-)

haliphax said...

What a fantastic snippet!

Harry Guillermo said...

I think there is an error in this line:
return (f = args.shift()) ? !!f(args) || !0 : !1;

!0 is true so the first part of the logical ternary is always true. It seems like that should be !1.

return (f = args.shift()) ? !!f(args) || !1 : !1;

Am it wrong?

Harry

Andrea Giammarchi said...

Harry you are wrong ... because the next() supposes to return true as long as there was something to call.

To be honest, I haven't used that so the script could be simplified like this:

function Queue(a,f){setTimeout(a.next=function(){(f=args.shift())&&f(args)},0);return a}

However, a more powerful version is here