Javascript Concepts

Google Maps API Tutorial

Javascript Concepts: Asynchronous I/O

In most computer languages, when you tell the program to read or write some data, the processing pauses until that action completes. The results of the read operation are available for use by the next statement in the program.

Most read and write operations in Javascript don’t work like that. Javascript makes a request to the I/O system for the data to be read or written and then continues to execute the following statements without waiting for the action to complete. When the action is completed, a corresponding completion event will be triggered.

If you want to be informed of the I/O completion, e.g. if you want to process the data that’s been read, you have to supply a callback function which will be called when the I/O completes. Or, in some cases, listen for an event that indicates that the operation is complete.

This makes sense when you consider that I/O operations which involve exchanging packets of data with Internet servers in distant parts of the world may take thousands of times longer to complete than I/O operations on your local peripherals. If the browser waited for one image to load before requesting the next, then it would take an awful lot longer for all the images to be displayed.

Images

Most of the time when you load an image, you’re not interested in knowing when the I/O has completed. In those cases when you do care, you can add an “onload” attribute to the <img> specifying the action to be performed when the image fetch is completed.

Alert

One example of an operation which is not asynchronous is “alert”. when you call alert(), all processing is paused until the user clicks the alert window’s “OK” button.

GDownloadUrl, GClientGeocoder and GDirections

GDownloadUrl, GClientGeocoder and GDirections calls are always asynchronous. There’s nothing you can do to make them synchronous.

The results of the I/O are not available immediately after the GDownloadUrl() call, but only within its callback function.

The results of a GDirections call are only available wne its “load” event has been triggered.

GXmlHttp

The method of using GXmlHttp() described in the documentation uses asynchronous processing.

If you really want to, you can use GXmlHttp() in synchronous mode. This is achieved by setting the third parameter of request.send() to false

     var request = GXmlHttp.create();
      request.open("GET", "example.xml", false);
      request.send(null);
      var xmlDoc = request.responseXML;

When used in this way, the “request.send()” will cause the processing to pause until the file has been fetched.

This works in standards-compliant browsers which don’t support ActiveX, and in MSIE6. There’s no guarantee that it will work in any other browsers that support ActiveX.

[The way the code works is that if the browser supports ActiveXObject, then GXmlHttp() calls ActiveXObject(“Microsoft.XMLHTTP”), if not, then if the browser supports window.XMLHttpRequest, then GXmlHttp() calls that. MSIE7 supports both technologies. The API is currently coded to use ActiveX if both are available. I’ve not tested synchronous GXmlHttp in MSIE7.]

onload functions

Another common situation where an asynchronous operation happens is when you use an onload function, either by writing <body onload=”load()”> in the HTML, or equivalently by writing window.onload=load;in the Javascript.

Code that’s placed outside any such function is executed as soon as the browser reads it, then the browser fetches any asyncronous resources that the page requires, in particular the images. After all the image fetches complete, the browser calls the onload function.

Advertisements

The Basics

Google Maps API Tutorial

XML

If you want to have dozens of markers on your page, it gets a bit cumbersome to manage them if you code them all in your Javascript as in the previous examples.

The preferred method for handling large numbers of markers is to store the data in an XML file.

It’s also possible to have an application (e.g. mySQL) running on your server which returns XML containing a different selection from the data depending on query information derived from what your users input. I’m not going to cover the mySQL side of things in this tutorial.

Here’s a simple example

You can see the XML data file that I used here

The code used GDownloadUrl() to send a request to read the file.

At some later time, the reply comes back and the callback funtion gets invoked.

Once the data has been read, the callback function can grab a collection of data from the XML tags

   var markers = xmlDoc.documentElement.getElementsByTagName("marker");

then for each of those tags extract the individual attribute fields

   var lat = parseFloat(markers[i].getAttribute("lat"));

Once all the data has been parsed, we can create the markers and the sidebar as in the previous examples.

Note that the code to insert the assembled sidebar information into its <div> must be inside the callback function.

XML attributes strings can’t contain the characters < or >. You have to use &lt; and &gt;, which will get converted to < and > as the XML data is read.

Instead of using XML attributes, it’s possible to lay out your XML data like this:

   <markers>
     <marker lat="43.65654" lng="-79.90138" label="Marker One">
      <infowindow>Some stuff to display in the&lt;br&gt;First Info Window</infowindow>
     </marker>
   </markers>

Or even like this, using CDATA:

   <markers>
     <marker lat="43.65654" lng="-79.90138" label="Marker One">
      <infowindow><![CDATA[
        Some stuff to display in the<br>First Info Window
      ]]></infowindow>
     </marker>
   </markers>

When using CDATA, is is not necessary to use &lt; and &gt; in the contained HTML.

XML formatted like this can be read with GXml.value, like this

   var html = GXml.value(markers[i].getElementsByTagName("infowindow")[0]);

Potential Pitfalls

  1. Be aware that Javascript i/o is asynchronous (so that the browser can get on with doing other things like fetching images if the i/o request takes a while to complete).
    If you’re used to programming languages that wait for i/o to complete, you might tend to put code that uses the data read from the XML file after the “GDownloadUrl()” code. That would be wrong because code placed there would get executed immediately rather than waiting for the data to arrive. Any code that acts on the retrieved data should be placed inside the callback function.
  2. All data returned from XML is considered to be strings of characters. You need to convert your latitude and longitude from strings to floating point numbers by using “parseFloat()”.
    In some circumstances, it might seem that you can get away without doing that, but then things can go horribly wrong later. if the Google code tries to perform arithmetic on values that are not numbers.
  3. Avoid attribute names that are reserved words in either Javascript or HTML.
    In particular “name” and “long” are reserved words.
  4. XML data strings can’t contain the characters &, < or >. You have to use &amp;, &lt; and &gt;, which will get converted to &, < and >.
  5. Don’t have blank lines or spaces before the first tag in your XML file.
  6. Don’t get confused between the array of marker objects “gmarkers[ ]” and the HTMLCollection of marker data “markers[ ]” that gets returned by getElementsByTagName(). You can’t do things like map.addOverlay(marker[i]) to a HTML data element.
  7. If you want to copy my example.xml file, use the “view source” option in your browser, rather than saving it from the normal browser screen. Some browsers display extra formatting characters which you don’t want to have in your copy. All browsers will convert things like &lt; and &gt; into < and > which are not permitted.