Progress Events

There are five types of events that developers can respond to in Native Client: progress, message, view change, focus, and input events (each described in the glossary below). This chapter describes how to monitor progress events (events that occur during the loading and execution of a Native Client module). This chapter assumes you are familiar with the material presented in the Technical Overview.

Module loading and progress events

The Native Client runtime reports a set of state changes during the module loading process by means of DOM progress events. This set of events is a direct port of the proposed W3C Progress Events standard (except for the crash event which is an extension of the W3C standard). The following table lists the events types reported by the Native Client runtime:

Event Description Number of times triggered When event is triggered How you might react to event
loadstart Native Client has started to load a Native Client module. once This is the first progress event triggered after the Native Client module is instantiated and initialized. Display a status message, such as “Loading...”
progress Part of the module has been loaded. zero or more After loadstart has been dispatched. Display a progress bar.
error The Native Client module failed to start execution (includes any error before or during initialization of the module). The lastError attribute (mentioned later) provides details on the error (initialization failed, sel_ldr did not start, and so on). zero or once After the last progress event has been dispatched, or after loadstart if no progress event was dispatched. Inform user that the application failed to load.
abort Loading of the Native Client module was aborted by the user. zero or once After the last progress event has been dispatched, or after loadstart if no progress event was dispatched. It’s not likely you will want to respond to this event.
load The Native Client module was successfully loaded, and execution was started. (The module was initialized successfully.) zero or once After the last progress event has been dispatched, or after loadstart if no progress event was dispatched. Remove the progress bar.
loadend Loading of the Native Client module has stopped. Load succeeded (load), failed (error), or was aborted (abort). once After an error, abort, or load event was dispatched. Indicate loading is over (regardless of failure or not).
crash The Native Client module is not responding (died on an assert() or exit()) after a successful load. This event is unique to Native Client and is not part of the W3C Progress Events standard. The exitStatus attribute provides the numeric exit status value. zero or once After a loadend. Notify user that the module did something illegal.

The sequence of events for a successful module load is as follows:

Event is dispatched ... then this task is attempted
loadstart load the manifest file
progress (first time) load the module
progress (subsequent times)  
load start executing the module
loadend  

Errors that occur during loading are logged to the JavaScript console in Google Chrome (select the menu icon menu-icon > Tools > JavaScript console).

Handling progress events

You should add event listeners in a <script> element to listen for these events before the <embed> element is parsed. For example, the following code adds a listener for the load event to a parent <div> element that also contains the Native Client <embed> element. First, the listener is attached. Then, when the listener <div> receives the load event, the JavaScript moduleDidLoad() function is called. The following code is excerpted from the example in getting_started/part1/:

<!--
Load the published pexe.
Note: Since this module does not use any real-estate in the browser, its
width and height are set to 0.

Note: The <embed> element is wrapped inside a <div>, which has both a 'load'
and a 'message' event listener attached.  This wrapping method is used
instead of attaching the event listeners directly to the <embed> element to
ensure that the listeners are active before the NaCl module 'load' event
fires.  This also allows you to use PPB_Messaging.PostMessage() (in C) or
pp::Instance.PostMessage() (in C++) from within the initialization code in
your module.
-->
<div id="listener">
  <script type="text/javascript">
    var listener = document.getElementById('listener');
    listener.addEventListener('load', moduleDidLoad, true);
    listener.addEventListener('message', handleMessage, true);
  </script>

  <embed id="hello_tutorial"
         width=0 height=0
         src="hello_tutorial.nmf"
         type="application/x-pnacl" />
</div>

Event listeners can be added to any DOM object. Since listeners set at the outermost scope capture events for their contained elements, you can set listeners on outer elements (including the <body> element) to handle events from inner elements. For more information, see the W3 specifications for event flow capture and event listener registration.

Displaying load status

One common response to progress events is to display the percentage of the module that has been loaded. In the load_progress example, when the progress event is triggered the moduleLoadProgress function is called. This function uses the lengthComputable, loaded, and total attributes (described in the proposed W3C Progress Events standard) of the event to calculate the percentage of the module that has loaded.

function moduleLoadProgress(event) {
  var loadPercent = 0.0;
  var loadPercentString;
  if (event.lengthComputable && event.total > 0) {
    loadPercent = event.loaded / event.total * 100.0;
    loadPercentString = loadPercent + '%';
    common.logMessage('progress: ' + event.url + ' ' + loadPercentString +
                     ' (' + event.loaded + ' of ' + event.total + ' bytes)');
  } else {
    // The total length is not yet known.
    common.logMessage('progress: Computing...');
  }
}

The lastError attribute

The <embed> element has a lastError attribute that is set to an informative string whenever a load failure (an error or abort event) occurs.

The following code adds an event listener before the <embed> element to capture and handle an error in loading the Native Client module. The handleError() function listens for an error event. When an error occurs, this function prints the contents of the lastError attribute (embed_element.lastError) as an alert.

function domContentLoaded(name, tc, config, width, height) {
  var listener = document.getElementById('listener');
  ...
  listener.addEventListener('error', moduleLoadError, true);
  ...
  common.createNaClModule(name, tc, config, width, height);
}

function moduleLoadError() {
  common.logMessage('error: ' + common.naclModule.lastError);
}

The readyState attribute

You can use the readyState attribute to monitor the loading process. This attribute is particularly useful if you don’t care about the details of individual progress events or when you want to poll for current load state without registering listeners. The value of readyState progresses as follows for a successful load:

Event readyState value
(before any events) undefined
loadstart 1
progress 3
load 4
loadend 4

The following code demonstrates how to monitor the loading process using the readyState attribute. As before, the script that adds the event listeners precedes the <embed> element so that the event listeners are in place before the progress events are generated.

<html>
...
  <body id="body">
    <div id="status_div">
    </div>
    <div id="listener_div">
      <script type="text/javascript">
         var stat = document.getElementById('status_div');
         function handleEvent(e) {
           var embed_element = document.getElementById('my_embed');
           stat.innerHTML +=
           '<br>' + e.type + ': readyState = ' + embed_element.readyState;
         }
         var listener_element = document.getElementById('listener_div');
         listener_element.addEventListener('loadstart', handleEvent, true);
         listener_element.addEventListener('progress', handleEvent, true);
         listener_element.addEventListener('load', handleEvent, true);
         listener_element.addEventListener('loadend', handleEvent, true);
      </script>
      <embed
        name="naclModule"
        id="my_embed"
        width=0 height=0
        src="my_example.nmf"
        type="application/x-pnacl" />
    </div>
  </body>
</html>

The exitStatus attribute

This read-only attribute is set if the application calls exit(n), abort(), or crashes. Since NaCl modules are event handlers, there is no need to call exit(n) in normal execution. If the module does exit or crash, the crash progress event is issued and the exitStatus attribute will contain the numeric value of the exit status:

  • In the case of explicit calls to exit(n), the numeric value will be n (between 0 and 255).
  • In the case of crashes and calls to abort(), the numeric value will be non-zero, but the exact value will depend on the chosen libc and the target architecture, and may change in the future. Applications should not rely on the exitStatus value being stable in these cases, but the value may nevertheless be useful for temporary debugging.