Originally published on naman34.svbtle.com
Eval is Evil. Douglas Crockford has made that so popular that any competent Javascript developer thinks twice before actually using eval. But when do we even need to use eval?
Sometime we need to actually affect the webpage by evaluating a string. Those are cases when there is no way around eval. However, in most cases, eval is usually used for testing, and providing an interactive coding experience in the browser for tutorials, demos and the like.
I recently ran into the problem while developing Imprezzive. Imprezzive is a modern web-based presentation framework that has been tailored especially for real-time editing and collaboration and sharing code samples.
One of the things I wanted to accomplish with Imprezzive was to provide a text editor within the slides where you could actually run the code and see the results. This is very useful for presenting code samples and showing off what they do. Also, as code editors were just floating elements like any other element, It was also possible to compare and contrast multiple approaches to a problem and determine their correctness and performance.
I solved this by using the Ace Editor with a custom theme that complemented my Tron-inspired presentation theme. I also added a mini-console under every Ace editor with a ‘Run Code’ button. A run code button is exactly the place where a developer would be tempted to use eval. I was too. But I remembered the wise words of Crockford.
I decided to do what eval does, but safely, in a web worker. A web worker has many benefits:
- It runs on a separate thread that keeps your UI thread safe from buggy code and slowdowns.
- It can throw errors safely
- It has a relatively good browser support.
However, it does have a few drawbacks. Web Workers run in their own context and have no access to the window object. As a results, code running in a web worker has no access to common ways we test code, such as alert, and the various methods on console.
It turns out, it’s very easy to ‘polyfill’ these methods in the web worker, and just stream the results back to the main thread. As an extra precaution, you should have some sort of run-time limit on the web worker, so you save yourself from infinite loops, even if they are on a separate thread.
This is the code that runs in your web worker. If you knew what the code would be running in advance, you could just this as a separate file and just run it without issues. However, one cool thing about Web Workers is that you can prepare a javascript string in your UI thread and just run it in a web worker. The process is simple enough, but there are a few steps involved. Here is the code I for Imprezzive.
One important piece of the solution was the setTimeout
at the end of the code. Just in case the user runs some code that ends up in an endless loop, we can kill the process, and save the computer from unnecessary work.
There are more edge cases that should be put in for a production system. For example, you should probably listen for an event that fires when the code finishes running and have special message in the console if the code had to be terminated early.
I hope this provided an easy way to use Web Workers effectively to run arbitrary code. However, Web Workers are powerful tools that can also be used in different contexts.