[HOME] jsMath (Authors) [Prev][Up][Skip][Next]

Synchronizing with jsMath

In versions of jsMath prior to 3.0, because the various jsMath files were loaded via <SCRIPT SRC="..."> tags, there were no real synchronization issues, since the JavaScript file in a SCRIPT tag would be loaded and executed before any of the following SCRIPT tags were processed. In version 3.0, a new file-loading mechanism was introduced, and this method runs asynchronously in some browsers, meaning that some commands may simply queue their actions for completion later, and so scripts that follow those commands may be executed before the actions of those commands are performed. This means that scripts must be careful to coordinate their actions, especially if one depends on the result the other. (See the change log for version 3.0 for a discussion of why this change was important.)

Some actions, like loading files, changing style sheets, processing mathematics, and so on, may not be completed when the jsMath functions that initiate them return. For example, jsMath.Setup.Script("plugins/tex2math.js") may start a file loading operation that runs asynchronously (i.e., your JavaScript will continue to run even while the plugin is being loaded). Moreover, if some other file load is already in progress when the jsMath.Setup.Script() command is called, the loading of tex2math is simply queued and will be performed later when the current file load is complete. In general, you will not know what state jsMath is in when you need to ask it to do something for you, and so you may need to synchronize your scripts with the events that jsMath is already processing.

(It would be a lot easier to do this if JavaScript had a command that would allow it to wait for a value to change. If that were true, functions like jsMath.Setup.Script could block until the file was fully loaded and then continue, making all this queuing and synchronizing unnecessary. Alas, that is not to be.)

To help you do this, jsMath provides the jsMath.Synchronize() command. It allows you to queue your own commands to be processed in turn by jsMath whenever it is finished doing what has already been queued. For example, if you use the commands

    <SCRIPT>
      jsMath.Setup.Script("plugins/tex2math.js");
      jsMath.Synchronize("alert('tex2math loaded')");
      alert('tex2math requested');
    </SCRIPT>
the 'tex2math loaded' alert would be guaranteed not to occur until after the tex2math plugin is loaded, while the 'tex2math requested' alert could occur before tex2math is loaded, depending on what else has happened before this, and on what browser is being used.

A number of jsMath commands call jsMath.Synchronize() internally, so they automatically synchronize properly. These include

jsMath.Process()
jsMath.ProcessBeforeShowing()
jsMath.ProcessElement()
jsMath.Setup.Script()
jsMath.Font.Load()
jsMath.Setup.Styles()
jsMath.Setup.Body()
jsMath.Extension.Require()
and the tex2math conversion functions
jsMath.ConvertTex()
jsMath.ConvertLaTeX()
jsMath.ConvertTeX2()
jsMath.CustomSearch() and
jsMath.ConvertCustom().
If you plan to modify jsMath or call on any other internal function, you should use jsMath.Synchronize() in order to guarantee that jsMath is in the proper state when your action is performed.

For example, if you want to call jsMath.Translate.ProcessElement(), you should do so using jsMath.Synchronize(), since you need to be sure that any fallback code has been fully loaded before you try to process the mathematics. Note that the jsMath.Translate.ProcessElement() can itself call jsMath.Synchronize() (for example, if jsMath needs to load an optional component needed by the math being processed), so when jsMath.Translate.ProcessElement() completes, you are not guaranteed that jsMath has finished handling the mathematics, and so if the rest of your script needs to use that mathematics (say to look up its size), then you will need to put the rest of the script in a second call to jsMath.Synchronize().


The Details of jsMath.Synchronize

The jsMath.Synchronize() command accepts two types of arguments: either a string or a JavaScript function reference. The example using alert('tex2math loaded') above used a string argument. An example using a function that accomplishes the same thing is the following:
    <SCRIPT>
      function afterLoad() {
        alert('tex2math loaded');
      }
      jsMath.Setup.Script("plugins/tex2math.js");
      jsMath.Synchronize(afterLoad);
    </SCRIPT>
You can use an anonymous function reference as well:
    <SCRIPT>
      jsMath.Setup.Script("plugins/tex2math.js");
      jsMath.Synchronize(function () {
        alert('tex2math loaded');
      });
    </SCRIPT>
Examples of this type are used throughout the author's documentation pages.

It is possible to pass a single argument to the function being called:

    <SCRIPT>
      function afterLoad(data) {
        alert('after tex2math with data "'+data+'"');
      }
      jsMath.Setup.Script("plugins/tex2math.js");
      jsMath.Synchronize(afterLoad,"fred");
    </SCRIPT>
will cause afterLoad("fred") to be executed after the tex2math plugin finishes loading. Although only one parameter can be passed, you can make that parameter be an array containing several values, as in the following:
    <SCRIPT>
      function afterLoad(data) {
        var item1 = data[0]; var item2 = data[1];
        alert('after tex2math with two items: "'+item1+'" and "'+item2+'"');
      }
      jsMath.Setup.Script("plugins/tex2math.js");
      jsMath.Synchronize(afterLoad,["foo","bar"]);
    </SCRIPT>
or alternatively
    <SCRIPT>
      jsMath.Setup.Script("plugins/tex2math.js");
      jsMath.Synchronize(function (data) {
        var item1 = data[0]; var item2 = data[1];
        alert('after tex2math with two items: "'+item1+'" and "'+item2+'"');
      },["foo","bar"]);
    </SCRIPT>

While not every jsMath call needs to be synchronized, it is hard to tell which ones do, so you are safest if you always synchronize when you interact with jsMath (other than with the commands listed above that already include synchronization). If there are no pending commands, your command will run immediately; but remember, your synchronized code may be queued for later operation, so you may need to continue to synchronize other commands that depend on their results.

Finally, the internals of the file-loading (and some other commands) are browser-dependent, and whether the loads are performed synchronously or asynchronously can vary from browser to browser and may even depend on the Control Panel settings. So testing your code in one browser may not be sufficient to guarantee that it will work with all browsers if you haven't been careful about synchronization. One good test to use is to check both the "force asynchronous processing" and the "show progress messages" checkboxes in the jsMath Options panel, then reload the page. If it works both with these and without these checked, chances are it will work with most browsers.



Get jsMath at SourceForge.net. Fast, secure and Free Open Source software downloads [HOME] jsMath web pages
Created: 10 Jul 2005
Last modified: 13 Sep 2008 15:04:21
Comments to: dpvc@union.edu
[Next] Making Your Own jsMath Fonts
[Skip] Browser Support for jsMath
[Up] Information for jsMath Authors
[Prev] Overriding jsMath Functions with Your Own Versions