Buffering Dynamic HTML
Wednesday, November 15, 2006 — 04:45
Fair warning: This post will have extremely nerdy content. But you probably could’ve guessed that from the title.
Story time. On our latest widget, we have to display a significant amount of HTML that has been generated by JavaScript. By “significant amount”, I mean 275 plus lines of information that was generated and displayed by JavaScript. I know that 275 doesn’t sound like much when there’s a computer doing it, but it seemed to be slowing stuff down.
To display the information I was “printing” I would print it directly from a loop with the data. The solution I came up with was to try to buffer the information.
— Start technical description —
To display something on the screen is often much slower than generating the information you want to display. The process of buffering allows you to generate the content and print it to an intermediate “buffer”, then print it to a screen all at once. The idea is that it’s much faster to print more information once than it is to print small bits lots of times. Wikipedia has more information of buffers.
— More technical description —
When I say “printing” I’m kinda lying. JavaScript and HTML don’t exactly have the low-level console-type printing that C has (printf() anyone?). Ok. Lying again. There is write(), but it doesn’t really work well for any purposes beyond very simple printing. JavaScript uses a property called .innerHTML. Ok. Moving on.
— End technical description —
Now, I had always assumed that buffering wasn’t really necessary when printing HTML code to the document. I thought that the data that’s being printed is so small that there isn’t really any need. However this changes as you add loads of information.
This is what was happening in our new widget. I didn’t think that buffering would change much, but when you’re talking 10-second cold-starts something has to be done. So, what I decided to do was set up a very-imformal experiment to test the effectiveness of buffering in a situation such as this. Here’s our situation:
- Printing out hundreds of lines of stuff through a loop.
- These lines have links.
- These lines also have dynamic content. I.e. content that is different for each iteration of the loop.
Based on these criteria, I created a test to see how well buffering works. I wrote a JavaScript function to run through printing 500 lines directly, and one to do it through buffering.
The results I got were pretty surprising. The un-buffered version took anywhere from 3 to 10 seconds to complete its task. The buffered version did it almost instantaneously.
Here’s the test files: the un-buffered version and the buffered one. Try it for yourself. (Disclaimer: only tested in WebKit. Gecko might do something completely different performance-wise.)
We’re Still Workin On It
Saturday, November 04, 2006 — 23:40
Yes, we are still working on this new widget that we’ve been teasering (cool, I invented a new word!). Here’s yet another teaser. This is a blurry image of the widget’s interface. If you care, it’s a motion blur created by Core Image Fun House. That’s a really fun app. You should try it if you haven’t. Oh right. The pic.
Keep in mind that I may have stretched, distorted, or recolored this image before applying the blur. Just a thought.
Math.random?
Sunday, October 22, 2006 — 17:23
Fair warning: This is a geeky post.
In a widget, the way you generate random numbers is through a JavaScript function called Math.random(). Random numbers are useful for lots of things: We use them in Old Faithful (has to do with refreshing the image), Uncle Sam (generating random quotes), and MadLibs (auto-generating random words).
However in Dashboard, the Math.random() function doesn’t truly generate random numbers. Each time you close and reopen a widget it gives you the same sequence of numbers. Here they are. (Note that these numbers have been multiplied by 1,000,000,000 and rounded there, for readability.)
- 7826
- 131537788
- 755605322
- 458650132
- 532767237
- 218959186
- 47044616
- 678864717
- 679296406
- 934692896
To prove my point, I’ve created a quick-and-really-dirty widget to demo this. Here it is: RandomDemo.zip. This widget will show you the first 10 random numbers. You’ll notice that the first time you run it, it has these exact numbers in the same order.
If you close the widget and re-open it (Note close and re-open; a simple Cmd + R refresh won’t do), you’ll get the same exact sequence of numbers. That’s the problem. Dashboard’s Math.random() gives you the same numbers each time you open it in a new widget. This is especially a problem for widgets that do stuff like generate random passwords, because everyone sees the same password. However, it’s also annoying to us because everyone sees the same Uncle Sam quote and MadLibs auto-generated output each time they re-open the widget.
We have found a way to work around this bug, but it’s messy, annoying, and it would be much, much simpler if Apple just fixed the Math.random() function in Dashboard. So please, Apple: Fix it, will ya?
More Hints
— 05:02
Well, this evening Austin just posted some hints on our new upcoming widget. But I couldn’t let him have all the fun. Here’s what this widget is not:
- This widget is NOT used to slice bananas. It just isn’t.
- This widget is NOT useful to anyone who could be called a “spy”. What does that mean? I’m not at liberty to say.
- This widget was NOT created while listening to White Stripes. It just wasn’t.
- This widget was NOT created with Leopard/Dashcode. Sorry, we don’t have Leopard yet.
- This widget is NOT an update.
- This widget is NOT testing on only PowerPC processors.1
- This widget is NOT being built for Yahoo! Widgets. At least right now. We may, or may not add that version before it’s released.
- No matter what Mason may say to the contrary, what Austin said is right. Mason did NOT help code it.
- Finally, this widget is NOT done. In highly technical terms this widget is what we call “barley working”. It still has to go through the “working”, “working well”, and “working perfectly” phases before we’ll release it.
1 In the past we’ve tested all of our widgets on PPC processors only. This isn’t a problem because widgets run identically on PPC and x86 processors. However, now we’ve got not just one, but two Intel machines around, so life is good.
Well, with that, I suppose I should get back to work as we move onto the “working” phase.
Build Widget
Saturday, October 21, 2006 — 20:39
In my day-to-day widget developing, I’ve developed a few shortcuts to help along the way. One is my “Build Widget” Automator action that I use as a Finder Plugin. You can see what it looks like in the image on the right.
In short, it will take a normal folder and turn it into a widget bundle in the Widgets folder. Here’s what it actually does:
- Gets the selected Finder item. WARNING: This is not necessarily the item you right-clicked on.
- Copy it to the Desktop. Because it uses the Desktop, you cannot have you widget’s folder on the Desktop.
- Rename the folder by adding ‘.wdgt’ onto the end.
- It then moves the
foldernew widget to the Widgets folder. - It will then ask you if you want to continue on and make the widget a .zip archive.
- If you clicked yes, it will create the .zip archive. These last two are hidden to save space.
Well, there you have it. Inside the workflow (pun intended) of one widget developer.
How I Spent My Weekend
Monday, October 16, 2006 — 22:12
Over the weekend, I worked a little on our newest widget. Here’s what I did.
- Changed ‘http’ to ‘https’. Oh yeah.
- Re-wrote the DOM processor. It’s actually much shorter now.
- Put in a little error handling. It’s not much, but it’s a start.
While it sound like I almost got nothing done, oh wait… I did get almost nothing done. Actually, Austin’s writing most of this one. What’s the widget? I can’t tell you; it’s not done yet!
