The abc’s of AMD

To help our JavaScript SDK users still grasping Dojo’s AMD pattern we thought it would be worthwhile to compare one of the ‘latest and greatest’ AMD samples to the same app written using the older legacy pattern and discuss the differences.

If you’d like to follow along, open Feature Layer – On demand mode and its legacy equivalent side by side.  Source code can be found here: AMD and legacy.

Before AMD, we relied on a series of calls to dojo.require() to load modules.  Once all modules were loaded and the page’s DOM was available, we used dojo.ready() to fire a function usually called ‘init’.

In contrast, when using AMD, modules are loaded asynchronously by default.  This allows multiple modules to be loaded simultaneously.  After all modules load, they are available within a callback function.

require([
    /*ordered list of modules to load*/
    "esri/map", "esri/InfoTemplate", "esri/layers/FeatureLayer",
    "dojo/parser", "dojo/domReady!"

/*Beginning of anonymous callback function 
which fires once all modules have loaded*/
], function( 
    
    /*Variable names to refer to each loaded module*/
    Map, InfoTemplate, FeatureLayer, 
    parser 
)   {                  /*Beginning of actual callback code*/
    parser.parse();
    map = new Map("mapDiv", { 
        basemap: "national-geographic",
        center: [-2.97, 53.41],
        zoom: 9
    });
	...
	
	}) /*Close the callback curly brace and require's parenthesis*/

Prior to AMD, a single object was used to namespace classes from a single global object. For instance, to create a new FeatureLayer or SimpleMarkerSymbol, we referenced esri.layers.FeatureLayer or esri.symbol.SimpleMarkerSymbol each time in our code.

Legacy:

dojo.require(“esri.layers.FeatureLayer”);
...
var featureLayer = new esri.layers.FeatureLayer("

AMD modules loaded by require() are passed as positional arguments in a callback function.  These arguments are used to instantiate classes without lengthy global names.

AMD:

require([
    "esri/map", … "esri/layers/FeatureLayer"
], function(
    Map, …, FeatureLayer,
...
var featureLayer = new FeatureLayer("

Its worth noting that with AMD, argument names for the callback provided to require() can be anything you’d like. That being said, both Dojo and Esri provide Preferred Argument Aliases tables and this makes porting code between applications more straightforward.  We have also built a simple AMD require generator application to streamline the process of creating a require() call that uses preferred module aliases.

The most important thing to remember is that the arguments are positional, which means that you have to be careful to ensure that your argument names are listed in the same order that you loaded your modules.  If this isn’t done your variables won’t refer to the module you expect them to.

You will also see that sometimes AMD samples load modules that weren’t loaded using dojo.require() before.  Some examples are: “esri/config”, “dojo/_base/Color”, and “dojo/dom”.

This gives us a reference to utility methods like dojo/dom.byId(), classes like dojo.Color and the esri configuration object with properties like esriConfig.defaults.io.proxyUrl without relying on a global namespace.

dojo.byId("messages").innerHTML = "hello";  //legacy

becomes

dom.byId("messages").innerHTML = "goodbye";   //AMD

Last (but not least), notice the position of the AMD loaded plugin “dojo/domReady!” within our list of modules.  Since this module doesn’t return an object with functions, we place it last intentionally so that it won’t accidently become associated with another module’s argument alias.

While loading modules using AMD requires a little more work up front, the pattern has several benefits.  The global namespace is avoided, referencing classes from modules requires less code, and application load performance can improve.  We think this makes migration well worth the effort.

Happy coding!

This entry was posted in App Developers, Developer and tagged , , . Bookmark the permalink.

Leave a Reply

One Comment

  1. kganz says:

    Thank you very much, that was the best, most concise explanation of the differences between the two methods.