Links

Patrick Mueller elsewhere: muellerware.org, twitter.com/pmuellr

Thursday, January 19, 2012

AMD - the good parts

Based my blog post yesterday "More on why AMD is Not the Answer", you might guess I'm an AMD-hater. I strive to not be negative, but sometimes I fail. Mea culpa.

I do have a number of issues with AMD. But I think it's also fair to point out "the good parts".

my background

I've only really played with a few AMD libraries/runtimes. I've been more fiddling around with ways of taking node/CommonJS-style modules, and making them consumable by AMD runtimes. The AMD runtimes I've played with the most are almond and (my own) modjewel. My focus has been on just the raw require() and define() functions.

But I follow a lot of the AMD chatter around the web, and have done at least reading and perusing through other AMD implementations. To find implementations of AMD, look at this list and search for "async". The ones I hear the most about are require.js, Dojo, PINF, and curl.

And now, "the good parts".

the code

Browsing the source repositories and web sites, you'll note that folks have spent a lot of time on the libraries - the code itself, documentation, test suites, support, etc. Great jobs, all. I know a lot of these libraries have been battle-tested by folks in positions to do pretty good battle-testing with them.

the evangelism

Special mention here to James Burke (not this one), who has done a spectacular job leading and evangelizing the AMD cause, both within the "JavaScript Module" community, and outside. In particular, he's been trying to get AMD support into popular libraries like jQuery, backbone, underscore and node.js. Sometimes with success, sometimes not. James has been cool and collected when dealing with jerks like me, pestering him with complaints, questions, requests and bug reports. Some open source communities can be cold and bitter places, but the AMD community is not one of those, and I'm sure that's in part due to James.

Thanks for all your hard work James!

the async support

AMD is an acronym for Asynchronous Module Definition. That first word, Asynchronous, is key. For the most part, if you're using JavaScript, you're living in a world of single-threaded processing, where long-running functions are implemented as asynchronous calls that take callback functions as arguments. It makes sense, at least in some cases, to extend this to the function of loading JavaScript code.

If you need to load JavaScript in an async fashion, AMD is designed for you, and uses existing async function patterns that JavaScript programmers should already be familiar with.

support for CommonJS

This is a touchy subject, because when you ask 10 people what "CommonJS" is, you'll get 15 different answers. For the purposes here, and really whenever I use the phrase "CommonJS", I'm technically referring to one of the Modules/1.x specifications, and more specifically, the general definitions of the require() function and the exports and module variables used in the body of a module. These general definitions are also applicable, with some differences, in node.js.

When I use the phrase "CommonJS", I am NEVER referring to the other specifications in the CommonJS specs stable (linked to above).

AMD supports this general definition of "CommonJS", in my book. Super double plus one good!

Aside: I'm looking for another 'name' to call my simplistic notion of CommonJS. So far, things like simple require()y support, seem to capture my intent. But you know how bad I am with naming.

the design for quick edit-debug cycles

One of the goals of AMD is to facilitate a quick edit-debug cycle while you are working on your JavaScript. To do this, AMD specifies that you wrap the body of your module in a specific type of function wrapper when you author it. Because of the way it's designed, these JavaScript files can be loaded directly with a <script src=> element in your HTML file, or via <script src=> elements injected into your live web page dynamically, by a library. This means that as soon as you save the JavaScript you're editing in your text editor/IDE, you can refresh the page in your browser without an intervening "build step" or special server processing - the same files you are editing are loaded directly in the browser.

the resources

Beyond just loading JavaScript code, AMD supports the notion of loading other things. The things you can load are determined by what Loader Plugins you have available. Examples include:

Coming from the Java world, this is familiar territory; see: Class.getResource*() methods. For the most part, I consider this to be amongst the core bits of functionality that a programming library should provide. It's a common pattern to ship data with your code, and you need some way to access it. And, of course, this resource loading is available in an async manner with AMD.

Aside: I'm not sure what the analog of this is in the node.js world. You can certainly do it by hand, making use of the __dirname global, and then performing i/o yourself. I'm just not sure if someone has wrapped this up nicely in a library yet.

the build

At the end of the day, hopefully, your web application is going to be available to some audience, who will be using it for realz. It's unlikely that you will want to continue to load your JavaScript code (and resources) as individual pieces as you do in development; instead, you'll want to concatenate and minimize your wads of goo to keep load time to a minimum for your customers.

And it seems like most AMD implementations provide a mechanism to do this.

Wednesday, January 18, 2012

More on why AMD is Not the Answer

Follow-on to Tom Dale's blog post "AMD is Not the Answer" and James Burke's response "Reply to Tom on AMD". I pretty much concur with everything Tom said. Here are some points brought up by James:

need an alternative

James says:

what is missing is a solid alternative to AMD. In particular, "use build tools to wrap up CommonJS modules" is not a generic solution. It does not allow for generic dynamic loading of resources, particularly from CDNs. Dynamic loading is needed for big sites that still do builds but want to stage loading of the site as the user uses it.

I don't think using build tools precludes you from building wads of modules that can be loaded dynamically. Generic solutions bother me. See: J2EE.

ceremony

James says:

On his concern about too much ceremony -- this is the minimum amount of ceremony:

    define(function(require) {
        //Module code in here
    });

On the other hand, here's some code pulled from dijit.Calendar.js:

    define([
        "dojo/_base/array", // array.map
        "dojo/date",
        "dojo/date/locale",
        "dojo/_base/declare", // declare
        "dojo/dom-attr", // domAttr.get
        "dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
        "dojo/_base/event", // event.stop
        "dojo/_base/kernel", // kernel.deprecated
        "dojo/keys", // keys
        "dojo/_base/lang", // lang.hitch
        "dojo/sniff", // has("ie")
        "./CalendarLite",
        "./_Widget",
        "./_CssStateMixin",
        "./_TemplatedMixin",
        "./form/DropDownButton"
    ], function(array, date, local, declare, domAttr, domClass, event, kernel, keys, lang, has,
                CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
        //Module code in here
    });

This isn't just ceremony. It's ugly ceremony of the sort that's difficult to debug when you screw up.

module consumption

James says:

the alternative he mentions does not handle the breadth of JS module consumption

The simple require()y story of npm modules seems to handle the JS module consumption pretty well, for node.js. For the browser, you can use npm modules with Browserify or other "build tools". Where is the equivalent of npm for AMD? Or maybe npm already contains AMD modules? Or let's say I want to just use a single module out of Dojo in my app. How do I do that?

Thursday, January 12, 2012

making Web SQL easier to use

One HTML5-ish area I've not yet played much with, but am starting to now, is Web SQL. Web SQL is the W3 standard for "SQL in the browser", which has been orphaned by the W3C. Here are some warnings from the Web SQL Database spec at w3.org:

  • "Beware. This specification is no longer in active maintenance and the Web Applications Working Group does not intend to maintain it further."

  • "This document was on the W3C Recommendation track but specification work has stopped. The specification reached an impasse: all interested implementors have used the same SQL backend (Sqlite), but we need multiple independent implementations to proceed along a standardisation path."

Despite the fact that the W3C no longer endorses Web SQL and will never 'standardize' it, implementations of Web SQL are shipping in browsers, including some mobile platforms. It's not dead yet.

what's the api like?

Here's an example right out of the spec, to count the number of rows in a table:

A function showDocCount()that calls a function db.readTransaction() that takes two anonymous functions as callbacks. One of those callbacks calls t.executeSql() passing it yet another callback, which finally, mercifully, gets the row count.

It's executing a single SQL statement.

But wait, it gets better.

If you need to run multiple SQL statements within a single transaction, you'll have to chain those executeSql() invocations within increasingly nested callbacks.

It's basically a horror show. At least as far as I'm concerned. Nested callbacks are things I hate to have to write, and things I really hate seeing other people have to write. The result is almost always unintelligible.

can we make this easier to understand?

For weinre, I implemented a stepper module used by the inspector's database interface. Not very clear what's going on there though, sorry.

The basic idea is that you provide an array of functions - the steps - that the stepper will arrange to run in order, by managing the callbacks itself. Double bonus good - you get to linearize your database transaction steps and you don't have to deal with callbacks!

I found another instance of this kind of processing in Caolan McMahon's async library - specifically the waterfall() function. Not really appropriate for Web SQL, but at least it seems to validate the approach.

I decided to implement a clean implementation of the stepper, trying to make it easy to use and understand. The result is available as WebSQLStepper at GitHub. As a use case, I took the Todos sample from Backbone, and modified it to use this library to persist the data to a Web SQL database. The complete sample is included in the GitHub repo, and here are the steps used to read all the rows of a database:

references

wr - an auto-build command for the command-line

For much of my programming career, I've been a user of "IDE"s, including BASIC, Turbo Pascal, various Smalltalks, IBM's VisualAge products and Eclipse.

Lately, I've been spending most of my time working without any IDEs. My tools are text editors, terminal windows, a boat load of unix commands built-in to my OS, some additional command-line tools from various open source locales, and web browsers. I think of this loosely organized/integrated set of tools as my IDE, they're just not packaged up in a nice single app.

But there's one thing I dearly love and really depend on in most IDE's that's missing from this command-line-based environment: an "auto-build" capability. Specifically, when I save a file I'm editing, I want a "build" to happen automagically. Without an "auto-build" capability, I'm left in a world where I save a change in my text editor, jump over to the terminal, run make, then jump to my browser to test the build. The jump to the terminal is not desired. Using some existing editor's capability of running shell commands doesn't work either, because I use a wide variety of tools to "edit" things - all the tools would need this capability.

(Quick aside about "builds". A lot of people see "build" and think "30 minutes of waiting for the compiles to be done". Yes, those builds are long and painful. I'm looking at you WebKit. But in all the IDEs I used to use, builds were insanely fast. Sub-second fast. If you're living the "big C++ project" lifestyle, I feel your pain, and "auto-build" is probably not applicable for you.

So, I'm talking about quick builds here. As an example, once you've done at least one build of weinre, subsequent builds take on the order of 6 seconds or so - I consider that slow, but it's doing a lot of work, and I could probably cut the time in half if I needed to - I just haven't felt the need to.)

a command to run something when a file changes

A few years ago, I wasn't aware of a tool that could watch for arbitrary file changes and run a command for me, so I wrote one - run-when-changed. This script served me well for a long time, but there were always little thingees I wanted to add to it. And since run-when-changed polled the file system to see when files changed, I was always interested in finding a better story than polling and the inevitable waiting for the polling cycle to hit - even waiting 3 seconds for run-when-changed to realize a file changed was bothersome.

A port to node.js seemed like it might be in order, especially since it has a non-polling file watch function fs.watch().

Earlier this week, I spent a few hours and now I have a replacement for run-when-changed, called wr, available at GitHub, written using node.js. The name wr comes from "watch and run".

Some features:

  • installable via npm

  • colorized stdout and stderr

  • reversed video status messages

  • when run with no arguments, will look for a .wr file in the current directory to use as arguments

Here's what it looks like, using it with one of my current projects:

Click the image for a slightly larger version.

Legend:

  • the reverse video blue lines are status messages
  • the reverse video green lines are command success messages
  • the reverse video red lines are command failure messages
  • the blue text is stdout
  • the red text is stderr

As another example, I'm generating this blog post by running the following command:

    wr --exec "markdown wr.md > wr.html" wr.md

Breaking this command down, we have:

  • wr - the command
  • --exec - a command-line option (see below in gotchas)
  • "markdown wr.md > wr.html" - the command to run
  • wr.md - the file to watch for changes.

The arguments to wr are options, the command to run, and the names of files or directories to watch. When the wr command is run, it waits for one of the specified files to change, runs the specified command, reports the results of running the command, and then starts waiting for a file to change again. Exit the program by pressing ^C.

The ability to store a .wr file in a project directory makes life even easier. I used to create a target in my make files to invoke run-which-changed ; now I just put the wr invocation for a project in the .wr file, and run wr with no arguments.

My work-flow for using wr goes something like this:

  • open a terminal window
  • cd into my project's home directory
  • launch an editor, returning control to the command-line
  • run wr
  • move the terminal window where I will always be able to see the last few lines of the window, to see the live status
  • switch between text editor and browser, for my edit-save-reload-test cycle, all day long, keeping an eye out for red stuff in the wr output
  • when the day is done, ^C out of wr, and then commit work to my SCM

This can all be yours, with a simple command-line incantation:

    sudo npm -g install wr

current gotchas

wr has two ways of invoking the command to run, determined by the command-line option --exec; see the README, in the ENVIRONMENT section, for more information on the differences.

The big gotcha though is the non-polling file watching. This is an awesome feature, as it means as soon as you save a file, wr will wake up and run a command. The problem, on the Mac anyway, is that there is a relatively small limit on the number of files that can be watched this way. Like, 200 or so. If you go over the limit, you'll see some error messages from wr, and you'll have to resort to using the --poll option, which uses a polling file watcher.

Friday, December 16, 2011

accessible backed up git repos for transient work-related projects

preface: this is basically a "note to self", but thought others might find it useful

I tend to create a lot of "projects" at work. A "project" is a directory in my "~/Projects" directory. Who knows what might be in it; probably code, or maybe just documentation. Many times, it's a "project" that I think may be useful to other people, and I may eventually "publish" to an either a public SCM repo farm like GitHub or an internal IBM SCM repo farm. I currently have 317 projects in my "~/Projects" directory.

Before "publishing" it though, I'll usually want to crank on it for a bit, see if I can get the crap to work, and figure out if it's actually useful. So there's a window where my project isn't being "backed up" or available to anyone else, because it's sitting on my laptop's spinning disk of rust. That's not great.

In the past, I've used Subversion and/or Mercurial to help manage this "back up" process for personal, non-work-related projects. What I'd do is set up a repo on my shared server, and then just use it like any other remote SCM.

Problems:

  • What about work-related stuff? I don't want to publish something that's work-related on a non-IBM site.

  • I made it sound like "set up a repo on my shared server" was easy. It isn't. Depending on the capabilities of your server, it might be impossible.

  • Yeah, we do have various internal-only SCM repo farms in IBM, but those still require some "setup" and "maintenance", just a different flavor than shared hosting, and even that can be too much sometimes. Especially for a project which may only be useful for a couple of days.

Bummer.

a new hope

What I'm doing now is using Git, and storing my Git repos on IBM's internal, backed up, rsync-/smb-/http-accessible cloud file store. Even if you don't have rsync or smb access, there are likely ways you can do something similar, with different tools, on your own server.

Here's how it works:

  • mount the file store on my local machine, create a directory for the new repo in my "git-repos" directory, which is in a part of my cloud file store that is publically accessible via http, unmount the file store.

  • initialize the project on my local machine with git (eg, "git init")

  • write a "backup" script, which looks like this:

    #!/bin/sh
    
    #--------------------------
    # make the git repo accessible via:
    #   git clone http://{host-name}/~pmuellr/git-repos/{project-name}/.git
    #--------------------------
    
    cd `dirname $0`
    
    git update-server-info
    rsync -av . {host-name}:{path-to}/git-repos/{project-name}
    
  • Instead of using a "git add/commit/push" workflow, I use a "git add/commit; ./backup" workflow.

  • As the comment in the script notes, the git repo is accessible via http, to anyone who has access to that URL. For the general case for me, that's anyone in IBM.

  • The "backup" script, as written, also backs up my working directory. Which is a win as far as I'm concerned. Now I can also point folks to web-accessible/-renderable resources in my working directory.

I've found this to be a very useful, very lightweight process to keep my immature projects backed up. I don't doubt there are ways to do similar things with SVN or Mercurial or whatever as well, I just never tried.

I can, but haven't yet, set up a similar story for personal projects, using my shared server, but that should be pretty easy; it supports rsync, but not smb. Instead of "mount and create project directory", I can "ssh and create project directory". Even that's probably not needed; rsync can likely create that project directory for me, but I'm an rsync n00b and I kind of like having to make that step explicit.

Wednesday, November 16, 2011

debugging concatenated JavaScript files

In James Burke's blog post "Why not AMD?", the subject of debugging briefly came up. In response to the claim that AMD is "Inefficient by default", James responds: (bold emphasis applied by me)

I assume this means that it allows separate modules to be loaded async. FWIW, the current state of ES harmony modules will allow separate file loading for each module. This works better for debugging.

For AMD, you can get the "one script file at the bottom of the page" loading with the 750 byte almond AMD shim and runtime http loading.

I cannot see a better solution to this issue. If you have ideas I would like to hear them.

I'd like to point out some futures/options for making concatenated scripts easier to debug. None of solutions deal with mangled names, they're just ways of letting the debugger show a concatenated script as the set of individual scripts that make up the concatenated script. Baby steps!

Source Map support in the web debuggers

Werner Schuster's blog post "Mozilla, WebKit To Support Debugging Minified JS As Well As CoffeeScript and other JS Languages" covers most of the ground for the Source Map work that's ongoing. Chris Heilmann's recent presentation from Velocity "Firefox Performance" mentions some work going on at Mozilla.

Of course, we need both ends working here; minizer's are going to have to be able to spit out Source Maps, as well as language translators like CoffeeScript. The CoffeeScript bug for Source Map work is here (I think).

cheating with eval() and //@ sourceurl

Back in the day, a feature in Firebug that I copied into Web Inspector was "sourceURL" support, described in "Give your eval a name with //@ sourceURL". I recently made use of this in my "unminified" version of the injected target weinre script. weinre ships with two versions of the code that gets injected into the target: target-script.js and target-script-min.js. The "min" version is what you should be using for typical weinre debugging, the non-"min" version is what I use when debugging the debugger.

The file target-script-min.js contains gently minized JS files, just concatenated together. The target-script.js file is a bit different. For every JS file, it adds a "//@ sourceurl" comment to the bottom of the file, converts the script content to a string with JSON.stringify(), and then writes an eval([that string here]) to the concatenated file.

The difference between debugging these in a browser which supports sourceurl is night and day. Try it: after visiting these pages, open your web debugger and look at the scripts which are loaded. Note, this works on Google Chrome 16.0.912.36 beta on a Mac (and likely other versions).

Sunday, October 30, 2011

what's new in weinre 1.6.0

Notable changes in weinre 1.6, which was released last week. More weinre links here.

Element Highlighter Color Changes

The "element highlighter" is the coloring you get on your web page when you hover over DOM elements in weinre's Elements panel. Previously, the colors were very muddled.

Below are the new colors, with the orange-ish margin, turquoise-ish padding, and purple-ish body. Not shown is the border (this element has none), which is a bright yellow.

There are still some issues with this highlighter, which was about the 6th different one I had tried. As a result of all those attempts, the element highlighter is now fairly pluggable, and it should be straight-forward for you to create a better one. I dare ya.

JavaScript Callback Error Diagnostics

I often hear people talk about debugging their JavaScript with weinre, but weinre really just provides a REPL and console logging. New in 1.6 is an attempt to provide some additional JavaScript diagnostics.

For a set of built-in functions in JavaScript that have callbacks as parameters, weinre overrides those functions to run an instrumented version of the callback instead. The instrumented version just runs the specified callback within a try/catch statement and reports if an exception occurred. The functions that weinre overrides are:

  • window.setTimeout()
  • window.setInterval()
  • window.addEventListener()
  • Node.prototype.addEventListener()
  • XMLHttpRequest.prototype.addEventListener()

The Node.prototype.addEventListener() override should handle document and all DOM elements in your document. The XMLHttpRequest.prototype.addEventListener() will handle your XHR's. Unfortunately, I'm not quite sure how to override the on-family of event properties, because browser host objects suck.

As an example of what you'll see in the Console window when an exception occurs, here's some JavaScript code which will generate a runtime error when the specified button is clicked:

Below is what you see in the console when the button is clicked.

Description of the five error messages in the console:

  1. This is the toString() of the exception that was caught when the callback was invoked.
  2. The callsite is an informational description of the call which registered the callback. In this case, it tells us the callback was registed to an <input> element's click handler, and that the callback registered was a function named buttonClicked().
  3. If the caught exception has a stack property, the stack will be dumped following this line. Otherwise, you won't see this line or the stack.
  4. This is the stack at the time the runtime exception occurred, if available. Note that the last two lines (at <error: TypeError: ...) seem to be bugs of some kind in the browser (couldn't be in my code!).
  5. This is actually a line from the new onerror handler that weinre registers, unrelated to the new callback exception logging described here.

Not all browser's JavaScript engines support the error.stack property (eg, WebKit's JavaScriptCore), so this is what you'll see if you're running on one of those lame engines:

Also note the third line is, again, from the new onerror handler, which seems to like to not contain useful information. Why not? See here, here, here, and here.

The New Resources Panel

The Resources panel is brand new for version 1.6. It provides diagnostics for all the XHRs that you code issues. Below is an example of a web page that has issued five XHR's.

Clicking on one of those rows will display additional information in the right hand side of the window, as shown below.

There are two tabs here, one to show "header" information, the other to show the "content". The content for the XHR is shown below.

To dismiss the detail view and get back to the table view, click the circled X button to the left of the Headers/Content tabs.

Friday, July 22, 2011

weinre 1.5.0 is now available

weinre 1.5.0 is now available at https://github.com/phonegap/weinre/downloads.

ChangeLog: http://phonegap.github.com/weinre/ChangeLog.html

I also went through and neutered the bits at the old "pmuellr/weinre" site. Everything should now, somehow, point you to the "phonegap/weinre" site/repo. Let me know if you see dangling pointers. (note, I'm not going to change links in my old blog posts)

Thursday, May 26, 2011

public weinre server hosted on the intertubes

Although I knew it was coming, the twitter post from Andrew Lunny yesterday made me very happy:

hosted weinre for PhoneGap Build is now live at http://debug.phonegap.com

Awesome! The fine folks at Nitobi are running this server, not me. Thank you so much! I owe everyone involved a cool beverage of your choice, next time we meet (OSCON?).

Of course, if you have any questions about using weinre, including this new public debug server, don't hesitate to ask:

some additional things to do for multi-user weinre servers

There's always more work to do, isn't there?

  • make the front page easier to use and understand, if required

  • optimize client and target resources - ok, this is kinda embarrassing, but the weinre server is not making use of some of the well-known best practices to optimize HTTP resource access

  • provide some hints / tips / best practices for folks wanting to run their own multi-user weinre server

In case you're wondering why someone would want to run another multi-user weinre server, now that we have one "in the cloud":

  • um, you're going to depend on the cloud?

  • there's not much security around the current weinre client/server interaction patterns, and there is at least the problem that the current debug packets are flowing across the internet in plain text. That includes, at a minimum, any serialized versions of DOM nodes that you are seeing in the DOM elements panel.

Given that, seems like it would make sense for organizations to run their own in-house weinre servers.

I'm planning on setting up a weinre server inside the IBM firewall for IBMers to use. I'll post news on that subject to the new weinre "Community" I set up on the IBM internal "Connections" page. To find that community, search for weinre, mobile, debug, etc.

Friday, May 20, 2011

callback debugging - better mobile error diagnostics

One of the common issues that comes up regarding debugging mobile web apps, is that the error diagnostics for JavaScript are terrible. Sometimes non-existent. Current state of the art is to turn on the "Debug Console" switch in Mobile Safari, which is kinda horrifying, but does provide some information. Or use low-level debug tools like Android's logcat. These tools provide additional clues about JavaScript errors that have occurred.

But I've wanted to add something to weinre, and a while back opened issue 38 - "provide better error handling - by hook or by crook". My first attempt was to try overriding some addEventListener() functions, which would instrument the callback methods passed to them. The instrumentation was to wrap the invocation of the original callback in a try/catch, and if something was caught, report it. The reason this is a good avenue to go down is that after the top-level JavaScript code in your HTML and JavaScript files runs, everything else is run because of a callback somewhere. If you can control the callbacks, you control JavaScript.

Aside, there's a number of interesting links in that bug report:

I decided to spend some time on the error diagnostics issue this week, but first did a cursory Google search, and found an article by Tom Robinson on the subject. Basically describes the approach I was heading down, so things still sounded promising.

Since I didn't see any kind of existing library to do this kinda stuff, I wrote one - CBWrapper. Putting it in a separate GitHub repository for now, because it's kind of a general purpose callback diagnostic tool. Could be useful in Node, perhaps. If it turns out to be useful and safe for weinre, I'll add it, but for now you can use it as a separate set of script files.

Here's what it can do. Keep in mind that the normal amount of JavaScript error handling you get in weinre is - nothing. Add the CBWrapper scripts as indicated on it's page, and you'll instead see the following output in the weinre console. Note that the information displayed is different depending on your web browser's JavaScript engine. I only tested under Mobile Safari and Android's Browser.

under JSC - all Apple devices and older Android devices

exception: TypeError: Result of expression 'xScript' [null] is not an object.
location:  https://[[url-elided]]/CBWrapper/tests/script-runtime-error-function.js:8
callback:  window.setTimeout(aScript(), 2000)

under V8 - newer Android devices

exception: TypeError: Cannot call method 'doSomething' of null
callback:  window.setTimeout(aScript(), 2000)
           [http://[[url-elided]]/CBWrapper/tests/test-weinre-runtime-function-script.html:10]
stack:
TypeError: Cannot call method 'doSomething' of null
    at bScript (http://[[url-elided]]/CBWrapper/tests/script-runtime-error-function.js:8:11)
    at aScript (http://[[url-elided]]/CBWrapper/tests/script-runtime-error-function.js:3:5)
    at cbWrapper (http://[[url-elided]]/CBWrapper/CBWrapper.js:253:27)
    at http://[[url-elided]]/target/target-script-min.js#test:3674:14

Curiously, the exception messages are wildly different here. The line that threw the exception was:

    xScript.doSomething() // where xScript == null

Note that besides the other information provided, there's a line labelled "callback", which gives you some information about the function that registered the callback that just threw the error. In this case, it was a window.setTimeout() call, and the message provides some contextual information on the call itself. The registration function is no longer on the stack, but I keep a reference to it in case you want it. Like in this case.

CBWrapper can do a lot more than log errors. It provides before/after callbacks before every callback that it wraps, so you can do things like get the elapsed time of all the callbacks, log callback events on the Web Inspector timeline, etc. In theory.

Practice, however, is a different story. Playing with it a bit, under weinre, led me to some issues. See, weinre itself uses some of the same callbacks that CBWrapper wraps, so it's pretty easy to fall into a trap where you do something in a CBWrapper callback (write to the console), which causes weinre code to set a timer or do an XHR, and you've just created an endless chain of console logs / CBWrapper callbacks that will never end. The callback-based async version of infinite recursion.

Finally, Kent Beck posted the following message on Twitter today:

the problem with callbacks triggering callbacks triggering callbacks is that when something goes wrong, reading the code doesn't help much

Seems like maybe you could whip something up with CBWrapper that could show you callbacks registered from other callbacks, and then show a trail of those callbacks when an error is thrown. Would that help? Only one way to find out and I'll leave that as an exercise for the reader.