Titanium Guides Project: JS Environment

Gold triangle pattern background, 3d rendering

Hi everybody,

In advance of our imminent 1.5 release (we’re working feverishly to finalize it and get it in your hands!), we’re putting together a set of tutorials based on the awesome Rails Guides site from the Ruby on Rails team.  It’s in an open source repository hosted on our corporate account, so feel free to watch, track, fork and contribute your own guides and improvements.

As a bit of a preview, you might want to check out one of the first completed guides, covering an area where we always get a lot of questions – the JavaScript Runtime environment of a Titanium Mobile application. In this guide, you will learn about the JavaScript runtime environment in which your application code executes – preview screen grab below:

Appcelerator Documentation Guides : The Titanium JavaScript Environment

An in-progress look at our guides site

The balance of the guide is included below – Enjoy!


The Titanium JavaScript Environment

In a Titanium Mobile application, your source code is packaged into a binary file and then interpreted at runtime by a JavaScript engine bundled in by the Titanium build process. In this guide, you will learn more about the JavaScript runtime environment that your code runs in.

The JavaScript Engine

Titanium runs your application’s JavaScript using one of two JavaScript interpreters – JavaScriptCore on iOS (the interpreter used by Webkit) and Mozilla Rhino on Android and BlackBerry. These engines provide a standard JavaScript interpreter with most of the functionality you would be used to in the web browser, with a few notable exceptions (mainly the DOM APIs and other browser-specific trappings). However, Titanium has supplemented the global namespace with some global functions JavaScript developers would be accustomed to.

Built-In Functions

There are a number of functions built into the global namespace in your mobile JavaScript application. They are formally addressed in the official API documentation, but we’ll enumerate several of these functions here to make you aware of them.

  • setTimeout – schedule a function to be called once after a certain number of milliseconds
  • setInterval– schedule a function to be called on a regular interval, specified in milliseconds
  • clearInterval– remove a function executing on interval
  • alert– display a simple native alert dialog with text (for quick and dirty visual debugging, in lieu of logging)
  • JSON– Titanium provides a standard JSON serialization/deserialization mechanism via the JSON namespace (JSON.parse and JSON.stringify)

The Titanium Namespace

In addition to the above built-in functions, Titanium-specific APIs are found in the Titanium namespace. Titanium is also aliased to Ti to save you some keystrokes, but they are equivalent. The Titanium namespace provides many functions, properties, and events that you can use to create a native mobile application – check out the reference documentation for more on what is available in the Ti namespace.

Execution Contexts

By default, a Titanium Mobile application has a single “execution context” in which an application runs. In our case, an “execution context” is similar to the single JavaScript thread provided to JavaScript applications in the web browser. Your application’s app.js file bootstraps your application and serves as the root application context. All variables declared in a context are available globally.

Including external JavaScript files

It is possible to include files in the current execution context, much like using a <script> tag in an HTML page.

Ti.include('myscript.js');

Scripts included into the current context via include are executed globally for the context, and are not affected by functional scope. Let’s say somescript.js contains a single variable declaration:

var something = true;

The following code in app.js:

Ti.include('somescript.js');

if (something) {
    Ti.API.info('something is true');
}

And this code are equivalent – notice that includes are always global, regardless of the scope they are called in:

(function() {
    Ti.include('somescript.js');
})();

if (something) {
    Ti.API.info('something is true');
}

Multiple execution contexts

Your application can have multiple execution contexts. New execution contexts are typically created by opening a new window that points to an external URL in its url property:

Ti.UI.createWindow({
    url:'window.js'
}).open();

When the window is opened, the script window.js is immediately run in a new execution context. If the preceding code were run in app.js, any variables or function declarations made in app.js would be unavailable:

figure

Passing data between contexts

It is possible to communicate across execution contexts using application-level events. Using Titanium’s custom event API, arbitrary JavaScript data structures can be sent and received in different execution contexts. Note that the ‘payload’ of your event must be JSON serializable, so business objects will not preserve any instance methods associated with them. The APIs used to fire and receive events are in the Ti.App namespace:

//to fire...

Ti.App.fireEvent('customEvent', {
    myData:true,
    someStuff:[
        'foo',
        'bar'
    ]
});

//to receive...

Ti.App.addEventListener('customEvent', function(eventData) {
    alert(eventData.someStuff[0]); //will alert 'foo'
});

The following illustrates how this might look in a very simple Titanium Mobile application:

sample

Should I use a single context or multiple contexts?

As is often the case in software development, the answer is “that depends”. Most of the time, it is probably advisable to use a single execution context, for a couple of reasons:

  • You can pass complex objects in custom events
  • You only include your libraries/dependencies only once, since there’s only one context

In most of the projects done by Appcelerator’s own Professional Services team on Titanium Mobile, a single execution context with multiple include-ed external files is used. However, there are instances where having multiple execution contexts is useful. For example, in our Kitchen Sink application, it is advantageous to have a ‘clean slate’ for every API usage example, so we don’t have to worry about polluting the global scope and can keep the examples easy. It could be there are other reasons to want or need this ‘clean slate’ in your own application. In fact, that brings up a good point…

Don’t pollute the global scope!

This is more of a general JavaScript best practice, since it is important in the web browser as well. Declaring a lot of global variables and functions in an execution context leaves your code at risk of colliding with its self or other included libraries. To avoid this, use closures and self-calling functions to encapsulate your code. A rational include file would look something like this:

var myAPI = {}; // This is a variable I intend to be
                // global, since I want
                // people who inculde my file to
                // have visibility to it

(function() {
    // put my implementation inside a self-calling function,
    // so I can go crazy with local functions and variables

    function helper() {
        //do stuff
    }

    var state_variable = true;

    //then, create a controlled public API...

    myAPI.doSomething = function() {
        //do something
    };
})();

These and other best practices are covered in the JavaScript Best Practices guide.

That’s all for now – thanks for checking out this guide, and we’ll have the rest finished shortly.

1 COMMENT

  1. “In most of the projects done by Appcelerator’s own Professional Services team on Titanium Mobile, a single execution context with multiple include-ed external files is used.”

    Can I assume then that this might be considered a best practice?

  2. @Aaron I guess you could say that – it just seems to be easier than maintaining state across many different contexts, unless you have a compelling reason to do so. And, of course, the fact that you will only load dependencies once makes a difference in larger apps on older hardware.

  3. Wow~! It’s very cool.
    The guide will make much easier to understand.
    I’m waiting for Ti 1.5.0 release.
    Since I’d made iPad App(Ment TV) and uploaded to AppStore with under Ti 1.3.3,
    I’m eager to have more stable and faster builder version of Titanium.

  4. Thanks so much…this is the kind of stuff I’ve been waiting for, because I’m just grappling with Titanium, and have felt that there was precious little “big picture” kind of stuff that explained the…for lack of a better term…overall development philosophy behind a Titanium App. (In terms of how I ought to be organizing my project, classes, etc., and how I should be representing a “screen”, and so forth.)

  5. I want to contribute by writing guides and help you writ the documentation, but i am not a rails guy, and i couldn’t find this *JS Environment* in the GitHub page to study it, and to get used to the templating syntax. plz help i’m very excited and want to work with you.

  6. Awesome work; Rails Guides is one of the best examples of documentation done right. Glad to see you’re addressing the issue of docs seriously; Titatium is slick but some of the docs clearly need more love, and this looks like it’s giving them just that.

  7. “In most of the projects done by Appcelerator’s own Professional Services team on Titanium Mobile, a single execution context with multiple include-ed external files is used.”

    I don’t quite understand how you do this. Do you constantly remove everything from the current window and re-add everything each time you change screen ? The whole KitchenSink application is built around the idea of “1 screen = 1 file”. I haven’t found any documentation suggesting that there is another way or explaining how to do it differently. The documentation referenced in github doesn’t address this issue either, simply stating that you can put your code in other files put saying nothing more. I’d be curious to see a non trivial application (with many different views) built with includes instead of views in different JS files.

    This is a major architecture difference, and require more documentation on how to do it. So far, I’ve passed global objects between views through Titanium.App. Unfortunately, while it works correctly on iOs it fails on Android (for functions in particular). I have several dozens files representing views. I wish I had know the trouble I was getting into by choosing this approach. I know feel screwed as it seems the only way to have my API accessible in all my views on Android is to reinclude all my files for each context, which is insane. Any tip on making the switch to a single context would be greatly appreciated.

    • I’m redoing a sample application (Snapost) in this style, but at a high level your application would:

      1.) In app.js, use Ti.include to include external JS files which contain functions that build your app’s UI components (windows and any sub views)
      2.) Have app.js open your initial window/tab group
      3.) Have the code that creates each window initialize its self with sub-views.

      Your logic to open/close windows inside your application would remain largely the same – the big change would be rather than having:

      Ti.UI.createWindow({
      title:'My Window',
      url:'initializeMyWindow.js'
      }).open();

      you would do (with this code included from an external file):

      function createMyWindow() {
      var myWindow = Ti.UI.createWindow({
      title:'My Window'
      });

      //Add any stuff my window needs...
      myWindow.add(Ti.UI.createLabel({
      text:'This is a cool window!'
      }));

      return myWindow;
      }

      createMyWindow().open();

      Where the function code replaces whatever

      initializeMyWindow.js

      does to Ti.UI.currentWindow.