Tuesday, March 22, 2011

Making the most of using the Mozilla Rhino Javascript Engine

If you are using the Mozilla Rhino Javascript Engine to run your javascript code from Java the you have probably found that the performance is not one of its strong points. There are, however, a few things you can do to improve it, especially if you are creating reoccurring contexts that use the same script files.
    1. Load javascript resources from some form of caching resource loader.
    2. Compile scripts into org.mozilla.javascript.Script objects and use them instead of compiling the script each time.
      1) This is should be pretty obvious but using a caching resource loader ensures that javascript resources are not read from disk multiple times. If you use a single caching resource loader for given application then you will end up on loading a given resource only once from disk. The Dojo Zazl Project source code contains an simple implementation of a caching resource loader. The resource loader interface and the caching implementation can be seen here

      2) Rhino provides an API for compiling javascript resources into Script objects. If your usage of Rhino involves loading the same set of javascript resources multiple times then using the compiled Script to instantiate instances improves performance significantly.

      For the Dojo Zazl project I wrote a RhinoClassLoader class that enables the compiling of the scripts and also uses a classloader as a script class cache store. Here is a snippet from the code showing the compliation :

      import org.mozilla.javascript.CompilerEnvirons;
      import org.mozilla.javascript.optimizer.ClassCompiler;
      ClassCompiler classCompiler = new ClassCompiler(new CompilerEnvirons());
      Object[] classBytes = classCompiler.compileToClassFiles(resource, fileName.replace('-', '_'), 1, name.replace('-', '_'));
      Class c = defineClass(name.replace('-', '_'), (byte[])classBytes[1], 0, ((byte[])classBytes[1]).length);

      You can see the full code for it here

      The loadClass method of the RhinoClassLoader uses the classloader cache by simply using the ClassLoader classes findLoadedClass method  :

      Class<?> c = findLoadedClass(name.replace('-', '_'));
      if (c != null) { 
          return c;
      }

      Usage is simply :

      RhinoClassLoader rcl = new RhinoClassLoader(resourceLoader);
      Object scriptIntance = rcl.loadJS(uri, context, thisObj);

      with the returned object being the instance of the script. The RhinoClassLoader uses the resourceLoader instance to load the javascript resource. If you use a caching version of the resource loader then you improve the efficiency even more.

      No comments:

      Post a Comment