Mock Asynchronous File System Example

This page contains a mock file system with a very simple synchronous and asynchronous API. It is modeled after Node.js's file system API.

The Challenge

Writing code that uses asynchronous APIs is difficult. Structuring that code well is even more difficult. First, take a look at the synchronous recursive listing example below. That code recursively visits the entire file system and outputs a tree representation of everything in it. Essentially, it implements ls -R.

Try writing the same recursive code using only the asynchronous API (and join). Your code should be as "parallel" as possible — you shouldn't wait for one stat call to return before doing the next stat call, for example.

Note that sometimes an asynchronous call may not ever call its callback (e.g., in the case of an error in the underlying system). You should handle this case as well. The "asynchronous stat timeout" should give you the tools necessary to do so.

Your code needn't return everything in the same order as the synchronous code. However, it should return exactly the same data. Every time.

A few other examples are provided to help you with JavaScript syntax that may be unfamiliar to you. Those examples should contain all of the low-level knowledge you need to make this happen.

The File System Code

The file system API can be accessed via the mockfs global on this page.

The implementation of mockfs is available on github. That file works as an AMD module, a CommonJS module, and also as plain JS. So, if you don't like working in this web page, you can download this file and include it with a <script> tag on a simple HTML page. Or, you can just open the development console here.

The File System API

mockfs.join(a, b)

Joins two paths, taking care to clean up any extra '/' characters.

mockfs.statSync(path)

Synchronous stat call.

On success, returns an object with two functions: isFile and isDirectory. These functions evaluate to a boolean indicating whether the stated path is a file or a directory, respectively.

On error, throws an Error object with a descriptive message.

mockfs.listSync(path)

Synchronous list call.

On success, returns an array of strings of the names of all objects (files, directories, etc.) at the specified path (one level deep). The names are relative (they do not include the full path). .. and . are not included. This is the approximate equivalent of ls.

mockfs.stat(path, callback)

Asynchronous stat call.

The callback gets two arguments (err, result). err is null if there is no error, or is a string if there is an error. result is an object as defined in mockfs.statSync.

mockfs.list(path, callback)

Asynchronous list call.

The callback gets two arguments (err, result). err is null if there is no error, or is a string if there is an error. result is an array as defined in mockfs.listSync.

output(foo)

Logging call.

Prints either a JSONified representation of foo (if possible) or the result of String(foo) to the output log on this page. The output log is prepended for each output call (new logs appear at the top).

Note: This function is not included in the mockfs.js file linked above.

Your code

Code you enter below will be executed when you click 'Run'.

Any globals you define (or modify) are in the page's global space, so you have the possibility of really messing things up. But if you do, just hit reload! Your code is automatically saved (using HTML5 local storage) as you edit it. The next time you visit this page, it'll be there waiting for you. (Of course, you execute some really crazy code, you might break that, too!)

Calls to output(foo) write to the log below. See documentation above for more details.

Examples

These examples are intended to demonstrate basic JavaScript syntax and basic usage of the API. That way, you can concentrate on the hard part: figuring out how to do complicated things with an asynchronous API.

Important: Loading these examples will replace (and throw away) any code you may have entered above.

Output