4

The following code is from Essential JavaScript Design Patterns For Beginners. Why is the setTimeout function used here?

var pubsub = {};
(function(q) {

    var topics = {},
        subUid = -1;

    q.publish = function(topic, args) {

        if (!topics[topic]) {
            return false;
        }

        setTimeout(function() {
            var subscribers = topics[topic],
                len = subscribers ? subscribers.length : 0;

            while (len--) {
                subscribers[len].func(topic, args);
            }
        }, 0);

        return true;

    };

    q.subscribe = function(topic, func) {

        if (!topics[topic]) {
            topics[topic] = [];
        }

        var token = (++subUid).toString();
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };

    q.unsubscribe = function(token) {
        for (var m in topics) {
            if (topics[m]) {
                for (var i = 0, j = topics[m].length; i < j; i++) {
                    if (topics[m][i].token === token) {
                        topics[m].splice(i, 1);
                        return token;
                    }
                }
            }
        }
        return false;
    };
}(pubsub));
skaffman
  • 398,947
  • 96
  • 818
  • 769
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • 1
    Relevant question http://stackoverflow.com/questions/5113840/using-settimeout-to-improve-responsiveness – Ben Aston Jan 17 '12 at 18:19

1 Answers1

2

This way the publish function returns immediately, in some way scheduling given code block to be executed immediately later (asynchronously).

Looks like it notifies a bunch of listeners, so the author wanted to run the notification loop later, not blocking the publish code. Also note that the result of notification (if any) is not needed for the client code.

A side effect is that if one of the subscribers throw an exception, the publish method is not affected (different call stack).

Maybe it is not idiomatic, but it is quite common pattern in JavaScript. Sometimes it is also used to let other events/timeout to run - especially in very long-running function.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • Thanks. So will the function supplied to setTimeout run on a different thread? – Ben Aston Jan 17 '12 at 18:11
  • @Ben: no threads in ECMAscript (forgetting about webworkers). It just means, that this job is added to the "UI queue" later. Javascript code runs in the same thread the browser updates the UI, all jobs are queued in a big message loop. Its the principle of cooperative multitasking. – jAndy Jan 17 '12 at 18:13
  • Well, there are no threas *per se* in JavaScript. Rather think about a queue of events running one after another in single worker thread. When `publish` returns, it releases the worker threads, which is immediately used to handle another event. It might be the `setTimeout` with 0. It may also be some other event that was waiting longer. See [this question](http://stackoverflow.com/questions/7266918). – Tomasz Nurkiewicz Jan 17 '12 at 18:14
  • Seeing as ECMAscript is single threaded does this merely permit the UI thread to take a breath before the publish function does its work? If so, might I instead expect to *also* see the setTimeout being used within the while(len--) loop to mitigate the potentially long running notification process? – Ben Aston Jan 17 '12 at 18:32
  • @Ben: I have never seen such pattern. Note that JavaScript is mostly asynchronous (e.g. AJAX), long-running blocking functions aren't that often. – Tomasz Nurkiewicz Jan 17 '12 at 18:35
  • @Tomasz thanks for your help. You say asynchronous, but given that JS runs on the browser UI thread, if I invoke a method that counts to a hundred million, that will surely block the UI (i.e. invocation is synchronous)? – Ben Aston Jan 17 '12 at 18:40
  • @Ben: Yes. you can even call AJAX synchronously, which might freeze the entire UI for seconds... – Tomasz Nurkiewicz Jan 17 '12 at 18:42