Planet Wolves

July 03, 2009

Aq

Not blocking the UI in tight JavaScript loops

Everyone’s written a JavaScript loop that just loops over all the {LIs, links, divs} on a page*, and it’s pretty standard. Something like

var lis = document.getElementsByTagName("li");
for (var i=0; i<lis.length; i++) { // yes this could be more efficient, don't care
  // do something here to lis[i]
};

or, if you’re using jQuery:

$("li").each(function() {
  // do something here to this
});

This is problematic if there are, say, 2000 LI elements on the page, and what you’re doing in the loop is semi-intensive (imagine you’re creating a couple of extra elements to append to each of those LIs, or something like that). The reason this is a problem is that JavaScript is single-threaded. A tight loop like this hangs the browser until it’s finished, you get the “this script has been running for a long time” dialog, and the user interface doesn’t update while you’re in this kind of loop. You might think: aha, this will take a long time, so I’ll have some sort of a progress monitor thing:

var lis = document.getElementsByTagName("li");
for (var i=0; i<lis.length; i++) { // yes this could be more efficient, don't care
  // do something here to lis[i]
  progressMonitor.innerHTML = "processing list item " + i; // fail
};

but that doesn’t work. What happens is that the browser freezes until the loop finishes. Annoying, but there it is.

One approach to getting around this is with timeouts rather than a for loop.

var lis = document.getElementsByTagName("li");
var counter = 0;
function doWork() {
  // do something here to lis[i]
  counter += 1;
  progressMonitor.innerHTML = "processing list item " + counter;
  if (counter < lis.length) {
    setTimeout(doWork, 1);
  }
};
setTimeout(doWork, 1);

so you move the bit of work you need to do into a function, and that function re-schedules itself repeatedly, using setTimeout. This time, your user interface will indeed update, and your progress monitor will show where you’re up to. There are a couple of caveats with this: it’ll take a bit longer, and you’re no longer guaranteed to have things processed in the order you expect, but they’re minor issues.

For doing this in jQuery, a tiny plugin:

jQuery.eachCallback = function(arr, process, callback) {
    var cnt = 0;
    function work() {
        var item = arr[cnt];
        process.apply(item);
        callback.apply(item, [cnt]);
        cnt += 1;
        if (cnt < arr.length) {
            setTimeout(work, 1);
        }
    }
    setTimeout(work, 1);
};
jQuery.fn.eachCallback = function(process, callback) {
    var cnt = 0;
    var jq = this;
    function work() {
        var item = jq.get(cnt);
        process.apply(item);
        callback.apply(item, [cnt]);
        cnt += 1;
        if (cnt < jq.length) {
            setTimeout(work, 1);
        }
    }
    setTimeout(work, 1);
};

and now you can do

$.eachCallback(someArray, function() {
  // "this" is the array item, just like $.each
}, function(loopcount) {
  // here you get to do some UI updating
  // loopcount is how far into the loop you are
});

$("li").eachCallback(function() {
  // do something to this
}, function(loopcount) {
  // update the UI
});

Not always a useful technique, but when you need it, you need it.

by sil at July 03, 2009 12:55 AM

June 29, 2009

David Goodwin

Timberhonger 10k Race - June 2009

I came 29th - with a time of 42 minutes 50 seconds - it was pretty hot, and I was therefore quite pleased with my time - which was better than last year.

thanks to the organisers; more info here

by David Goodwin at June 29, 2009 06:38 AM

June 28, 2009

Peter Cannon

Sunday Update

Its been a while since I posted anything here,  to be honest I've been really busy what with LugRadio Live stuff my other blog on http://www.archlinux.me/dick_turpin Micro Blogging not to mention IRC.

Now I'm working on yet another project which is going to be awesome and is to do with AcrhLinux. I cant say too much yet but most of the stuff is in place its just a case of putting all together.

by joomla-admin@cannon-linux.co.uk (Peter Cannon) at June 28, 2009 09:56 AM

June 27, 2009

Jono Bacon

Tracking Ubuntu Community Issues

Recently Melissa wrote a post about how we track problems with community, and how she feels that blogging about community problems is a reasonable approach. As part of her post she says:

Blogging about problems we see in our community should be seen as a good thing, not a bad thing. Why? Because this blogging is action. The alternative is no action, and that is much worse.

Firstly, I entirely agree with Melissa that we need a better way to track issues with community, which I will get to a little later in this post. While blogging has become a tremendous tool in online communities and enabled community members to have a platform in which to share their opinions, ideas, perspectives and achievements, I don’t feel blogging is the most suitable means of tracking community issues, improvements and regressions.

Blog entries are single shot capsules of feedback, wisdom and opinion ejected onto the Internet and often aggregated in places such as Planet Ubuntu. They are typically highly personalized, lurking in personally-driven locations (such as a homepage or personal blog), have no facilities for applying status, assignment, milestones or priority, provide little or no means to subscribe to specific problems, and lack facilities for communicating when a problem has been solved: if the issue is resolved the blog is sometimes updated and sometimes not.

While a blog entry can express a concern about something, they are not really useful for finding solutions to the problem. Notification of a problem is one tiny element in the issue-tracking process and although blogs can indeed be used for this, it is equivalent to asking your neighbour to move his car by opening your window and yelling out through a loudspeaker. Aside from more elegant and better directed methods of communicating that a problem exists, we ideally want to attach problem-solving capabilities to the reporting of an issue: I care only a small amount about hearing the problem, what I am really interested in is collaborating with that person and others in trying to find a solution. Blog entries are not really cut out for that kind of collaboration.

Bugs are though.

Bug reporting systems were designed to allow people to collaborate around defects in software and include facilities to identify, track, prioritize, milestone, subscribe and share information. Although everyone complains about bug reporting systems, they are generally productive in finding problems, developing solutions and having visibility over the lifespan of a problem.

I think it could be useful for us to use Launchpad for filing bugs for community, process and governance issues. To this end I have registered the Ubuntu Community project in Launchpad which we can use for tracking these kinds of bugs. There are some benefits to this:

  • Visibility - this is going to help everyone keep visible on community issues. On a slightly selfish note, this will also help me keep visibility over issues for me and my team at Canonical. This should mean more bang for your buck with your friendly horsemen.
  • Tracking / Triage - this will make tracking, prioritization, feedback and potential milestoning much easier.
  • Assignment - this improved visibility will help us assign bugs better to the right people.
  • Familiar - many of us live and breath bug reports: the interface is part of the furniture. No new systems to learn, no random blog entries to keep an eye on.

Before I wrap up, there is one simple caveat here. I have literally just set up the project this afternoon and we will need some documentation, guidance and best practise written and shared around these bugs, and this will take a little while to be developed. As such, you may have some questions which we will need to document the answers to over the coming weeks. In the meantime we can work with existing bugs and file new bugs there. Feedback on this is of course welcome!

by jono at June 27, 2009 12:57 AM

June 26, 2009

Aq

Why not to use domain sockets for a desktop CouchDB

The obvious idea that pops into everyone’s head, including mine, when talking about having a running CouchDB that’s specific to me is: why use TCP for it? Why not just use a unix domain socket? Then you don’t have to worry about other people on the same machine trying to access it. Everyone thinks this, and on balance it’s not the way to go. This is why.

  1. You can’t browse to a unix domain socket in your web browser. This, by itself, is enough to kill the idea for me. I genuinely love the idea that applications store their data and then I can see that data in my browser using Futon, the CouchDB web UI. I can edit that data. That’s fantastic. Using unix sockets would break that.
  2. One other nice thing about CouchDB is that you can do replication between two different databases; I like this because I can have the same data on my laptop and my netbook if I want. That doesn’t work if you use domain sockets, because the two CouchDBs can’t see one another.
  3. As far as I can tell, Mochiweb, the underlying Erlang HTTP library that Couch uses, doesn’t do domain sockets anyway. (Obviously fixing this is only a Small Matter Of Programming.)

This has been a public service broadcast on behalf of the Write These Reasons Down So I Have Them To Hand Next Time Someone Suggests Unix Domain Sockets party.

by sil at June 26, 2009 09:47 AM