.. _devcycle-progress-events:
.. include:: /migration/deprecation.inc
###############
Progress Events
###############
.. contents::
:local:
:backlinks: none
:depth: 2
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 section describes how to monitor progress events (events
that occur during the loading and execution of a Native Client module). This
section assumes you are familiar with the material presented in the
:doc:`Technical Overview <../../overview>`.
.. Note::
:class: note
The load_progress example illustrates progress event handling. You can find
this code in the ``/pepper_<version>/examples/tutorial/load_progress/``
directory in the Native Client SDK download.
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
<http://www.w3.org/TR/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 | Times | When | How you might |
| | triggered | triggered | respond |
+==================================+===========+===============+===============+
|``loadstart`` | once | The | Display a |
| Native Client has started to | | first | status |
| load a Native Client module. | | progress | message, such |
| | | event | as |
| | | after the | "Loading..." |
| | | Native Client | |
| | | module is | |
| | | instantiated | |
| | | and | |
| | | initialized. | |
+----------------------------------+-----------+---------------+---------------+
|``progress`` | zero or | After | Display a |
| Part of the module has been | more | ``loadstart`` | progress bar. |
| loaded. | | has been | |
| | | dispatched. | |
+----------------------------------+-----------+---------------+---------------+
|``error`` | zero or | After the last| Inform user |
| The Native Client module failed | once | ``progress`` | that the |
| to start execution (includes any| | event has been| application |
| error before or during | | dispatched, | failed to |
| initialization of the module). | | or after | load. |
| The ``lastError`` attribute | | ``loadstart`` | |
| (mentioned later) provides | | if no | |
| details on the error | | ``progress`` | |
| (initialization failed, sel_ldr | | event was | |
| did not start, and so on). | | dispatched. | |
+----------------------------------+-----------+---------------+---------------+
|``abort`` | zero or | After the last| It's not |
| Loading of the NativeClient | once | ``progress`` | likely you |
| module was aborted by the user. | | event has been| will want to |
| | | dispatched, or| respond to |
| | | after | this event. |
| | | ``loadstart`` | |
| | | if no | |
| | | ``progress`` | |
| | | event was | |
| | | dispatched. | |
+----------------------------------+-----------+---------------+---------------+
|``load`` | zero or | After the | Remove the |
| The Native Client module was | once | last | progress bar. |
| successfully loaded, and | | ``progress`` | |
| execution was started. | | event has been| |
| (The module was initialized | | dispatched, or| |
| successfully.) | | after | |
| | | ``loadstart`` | |
| | | if no | |
| | | ``progress`` | |
| | | event was | |
| | | dispatched. | |
+----------------------------------+-----------+---------------+---------------+
|``loadend`` | once | After an | Indicate |
| Loading of the Native Client | | ``error``, | loading is |
| module has stopped. Load | | ``abort``, or | over |
| succeeded (``load``), failed | | ``load`` | (regardless of|
| (``error``), or was aborted | | event was | failure or |
| (``abort``). | | dispatched. | not). |
+----------------------------------+-----------+---------------+---------------+
|``crash`` | zero or | After a | Notify user |
| The Native Client module is not | once | ``loadend``. | that the |
| responding (died on an | | | module did |
| ``assert()`` or ``exit()``) | | | something |
| after a successful load. This | | | illegal. |
| event is unique to Native Client| | | |
| and is not part of the W3C | | | |
| Progress Events standard. The | | | |
| ``exitStatus`` attribute | | | |
| provides the numeric exit | | | |
| status. | | | |
+----------------------------------+-----------+---------------+---------------+
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).
.. |menu-icon| image:: /images/menu-icon.png
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/``:
.. naclcode::
<!--
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
<http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture>`_ and
`event listener registration
<http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-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 <http://www.w3.org/TR/progress-events/>`_
standard) of the event to calculate the percentage of the module that has
loaded.
.. naclcode::
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.
.. naclcode::
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.
.. naclcode::
<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.