2.6 - Asynchronous File Loading

We discussed in a previous lesson that a WebGL program is stored on a server, downloaded to a client’s computer, and then executed. Since a WebGL program is composed of multiple files, your WebGL program needs to wait until it has all of its required files before it starts rendering. This is a little tricky since the files are coming over the Internet where files are not guaranteed to arrive in the same order they are requested. And browsers are not required to download files in a particular order. You have probably seen this behaviour for web pages that contain many large pictures. Many browsers will download the pictures that are currently visible on the screen, regardless of the order they are specified in the HTML document. The technical name for this is asynchronous file loading.

Requesting file downloads

There are two basic ways for a web page to request a file from the server. The most straightforward way is to include a reference to it in the HTML description of the page. The following are several examples of file downloads:

<script src="../../lib/jquery.js"></script>
<link rel="stylesheet" href="../../lib/webglcode.css" />
<img src="picture.jpg">
<object width="400" height="400" data="model.obj"></object>

It is not obvious, but some types of these file downloads become visible elements on the web page, while others do not. In the above example, the data downloaded from the script and link tags are never visible on the page. However, the data downloaded from the img and object tags become part of the visible page. You can set special properties on the HTML elements to hide them, but why go to all the trouble when there is a second way to download files using JavaScript?

In JavaScript you can request that a file be downloaded and then ask JavaScript to “please call this specific function” when the file is ready for processing. This “processing function” is called a callback function because it is called at some future time when some event has happened. The event in this case is the successful download of a file. Why is this necessary? Because files are being downloaded asynchronously from the server and you don’t want your JavaScript code to “hang” waiting for a file to download, especially if the file is large.

The $.get(url, callback(data)) jQuery function will retrieve a file from a server and then call the callback(data) function when the file is totally downloaded and ready for processing. The one parameter, data, is the contents of the file. This is all fairly straightforward except the callback function can only have the one parameter, data. If you are downloading multiple files, you would have to have a separate function for each downloaded file, which is not practical. This is where the idea of a JavaScript context comes in very handy. Remember, JavaScript functions are always executed in a context. Consider the following code example:

function getFile(file_url, storage) {
  $.get(file_url, function (data) { storage.push(data); });
}

The $.get() function has two parameters: 1) a string that contains a universal resource locator (URL), such as “../lib/example.txt”, and 2) a callback function to receive the data and do something with it. The callback function is an anonymous function – it has no explicit name – because it doesn’t need a name. But here is the weird part. The callback function will be called in the context of the getFile() function. This means that the callback function has access to all the variables that getFile() knows about. Therefore it can access the storage variable and change it.

The technical name for this language feature is closure. There is no need to become an expert at closure code, but because of the way that JavaScript works, closures are often the only way to get asynchronous tasks accomplished.

The SceneDownload Object

For a WebGL program we need to download several types of data files from the server:

  • model data for our 3D scene objects
  • material descriptions that define model surface properties including texture maps, and
  • WebGL shader programs for rendering.

The number of these files will depend on the complexity of your scene and the complexity of the rendering. We will be using a JavaScript object called SceneDownload to download all of these files. When you create a SceneDownload object, you pass it a list of shader file names and a list of model file names. The constructor determines how many files it needs to download by adding the number of files in each list together:

downloads_needed = shader_list.length + model_list.length;
number_retrieved = 0;

It then proceeds to call $.get() for each required file. After each successful download it saves the data in an object, increments number_retrieved by one, and calls a function called _initializeRendering(). This function only starts the WebGL rendering of its canvas when all of the required files have been retrieved. The function looks like this:

function _initializeRendering() {

  if (number_retrieved >= downloads_needed) {
    // Pre-process the model data
    // Start rendering the canvas
  }
}

Glossary

synchronous
something that occurs at the same time.
asynchronous
a process that operates independently of other processes; not synchronous
asynchronous file loading
files are downloaded from a server, but the order and timing of the downloads is not directly controlled by a web programmer.
closure
an inner function has access to the outer (enclosing) function’s variables, even after the execution of the outer function has terminated.

Self-Assessments

    Q-53: Since browsers perform asynchronous file downloading, what order will these files be retrieved from the server?

    <script src="../learn_webgl/glpoint4.js"></script>
    <script src="../learn_webgl/glvector3.js"></script>
    <script src="../learn_webgl/glmatrix4x4.js"></script>
    <script src="../learn_webgl/obj_to_arrays.js"></script>
    
  • unknown!
  • Correct. The files could be retrieved in any order.
  • in the order they are specified: glpoint4.js, glvector3.js, glmatrix4x4.js, and then obj_to_arrays.js
  • Incorrect, though they might be downloaded in this order.
  • in reverse order to what they are specified: obj_to_arrays.js, glmatrix4x4.js, glvector3.js, and then glpoint4.js.
  • Incorrect, though they might be downloaded in this order.
  • an order based on their code dependencies.
  • Incorrect, because JavaScript does not currently support code dependencies.

    Q-54: In the getFile function below, what does function (data) { storage.push(data); } define?

    function getFile(file_url, storage) {
      $.get(file_url, function (data) { storage.push(data); });
    }
    
  • An anonymous callback function that will be executed after a file has been successfully downloaded from the server.
  • Correct.
  • A sub-function that is executed immediately.
  • Incorrect. It does define a sub-function, but it is not executed until something specific happens.
  • A sub-function that is executed asynchronously.
  • Incorrect. It does define a sub-function, but asynchronous execution implies random execution, which is not true.
  • An anonymous callback function that will be executed on "file events".
  • Incorrect. It does define an anonymous callback function, but there is no such thing as generic "file events."
    Q-55: A SceneDownload object retrieved which type of files? (Select all that apply.)
  • Shader programs.
  • Correct.
  • Model descriptions.
  • Correct.
  • Model material descriptions.
  • Correct.
  • JavaScript programs.
  • Incorrect. JavaScript programs are easily downloaded from <script> tags in the HTML code.
Next Section - 2.7 - Events