blob: b2a5e574fe977d30cc788fe5c3647d616752396a [file] [log] [blame]
{{+bindTo:partials.standard_nacl_api}}
<section id="progress-events">
<h1 id="progress-events">Progress Events</h1>
<div class="contents local" id="contents" style="display: none">
<ul class="small-gap">
<li><a class="reference internal" href="#module-loading-and-progress-events" id="id3">Module loading and progress events</a></li>
<li><a class="reference internal" href="#handling-progress-events" id="id4">Handling progress events</a></li>
<li><a class="reference internal" href="#displaying-load-status" id="id5">Displaying load status</a></li>
<li><a class="reference internal" href="#the-lasterror-attribute" id="id6">The <code>lastError</code> attribute</a></li>
<li><a class="reference internal" href="#the-readystate-attribute" id="id7">The <code>readyState</code> attribute</a></li>
<li><a class="reference internal" href="#the-exitstatus-attribute" id="id8">The <code>exitStatus</code> attribute</a></li>
</ul>
</div><p>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
<a class="reference internal" href="/native-client/overview.html"><em>Technical Overview</em></a>.</p>
<aside class="note">
The load_progress example illustrates progress event handling. You can find
this code in the <code>/examples/tutorial/load_progress/</code> directory in the Native
Client SDK download.
</aside>
<h2 id="module-loading-and-progress-events">Module loading and progress events</h2>
<p>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 <a class="reference external" href="http://www.w3.org/TR/progress-events/">Progress Events</a> standard (except for the <code>crash</code>
event which is an extension of the W3C standard). The following table lists the
events types reported by the Native Client runtime:</p>
<table border="1" class="docutils">
<colgroup>
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Event</th>
<th class="head">Description</th>
<th class="head">Number of
times
triggered</th>
<th class="head">When event is
triggered</th>
<th class="head">How you might
react to
event</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code>loadstart</code></td>
<td>Native Client has
started to load a
Native Client
module.</td>
<td>once</td>
<td>This is the
first
progress
event
triggered
after the
Native Client
module is
instantiated
and
initialized.</td>
<td>Display a
status
message, such
as
&#8220;Loading...&#8221;</td>
</tr>
<tr class="row-odd"><td><code>progress</code></td>
<td>Part of the module
has been loaded.</td>
<td>zero or
more</td>
<td>After
<code>loadstart</code>
has been
dispatched.</td>
<td>Display a
progress bar.</td>
</tr>
<tr class="row-even"><td><code>error</code></td>
<td>The Native Client
module failed to
start execution
(includes any
error before or
during
initialization of
the module). The
<code>lastError</code>
attribute
(mentioned later)
provides details
on the error
(initialization
failed, sel_ldr
did not start,
and so on).</td>
<td>zero or
once</td>
<td>After the
last
<code>progress</code>
event has
been
dispatched,
or after
<code>loadstart</code>
if no
<code>progress</code>
event was
dispatched.</td>
<td>Inform user
that the
application
failed to
load.</td>
</tr>
<tr class="row-odd"><td><code>abort</code></td>
<td>Loading of the
Native Client
module was
aborted by the
user.</td>
<td>zero or
once</td>
<td>After the
last
<code>progress</code>
event has
been
dispatched,
or after
<code>loadstart</code>
if no
<code>progress</code>
event was
dispatched.</td>
<td>It&#8217;s not
likely you
will want to
respond to
this event.</td>
</tr>
<tr class="row-even"><td><code>load</code></td>
<td>The Native Client
module was
successfully
loaded, and
execution was
started. (The
module was
initialized
successfully.)</td>
<td>zero or
once</td>
<td>After the
last
<code>progress</code>
event has
been
dispatched,
or after
<code>loadstart</code>
if no
<code>progress</code>
event was
dispatched.</td>
<td>Remove the
progress bar.</td>
</tr>
<tr class="row-odd"><td><code>loadend</code></td>
<td>Loading of the
Native Client
module has
stopped. Load
succeeded
(<code>load</code>),
failed
(<code>error</code>), or
was aborted
(<code>abort</code>).</td>
<td>once</td>
<td>After an
<code>error</code>,
<code>abort</code>, or
<code>load</code>
event was
dispatched.</td>
<td>Indicate
loading is
over
(regardless
of failure or
not).</td>
</tr>
<tr class="row-even"><td><code>crash</code></td>
<td>The Native Client
module is not
responding (died
on an
<code>assert()</code> or
<code>exit()</code>) after
a successful
load. This event
is unique to
Native Client and
is not part of
the W3C Progress
Events standard.
The <code>exitStatus</code>
attribute provides
the numeric exit
status value.</td>
<td>zero or
once</td>
<td>After a
<code>loadend</code>.</td>
<td>Notify user
that the
module did
something
illegal.</td>
</tr>
</tbody>
</table>
<p>The sequence of events for a successful module load is as follows:</p>
<table border="1" class="docutils">
<colgroup>
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Event is dispatched</th>
<th class="head">... then this task is attempted</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code>loadstart</code></td>
<td>load the manifest file</td>
</tr>
<tr class="row-odd"><td><code>progress</code> (first time)</td>
<td>load the module</td>
</tr>
<tr class="row-even"><td><code>progress</code> (subsequent times)</td>
<td>&nbsp;</td>
</tr>
<tr class="row-odd"><td><code>load</code></td>
<td>start executing the module</td>
</tr>
<tr class="row-even"><td><code>loadend</code></td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>Errors that occur during loading are logged to the JavaScript console in Google
Chrome (select the menu icon <img alt="menu-icon" src="/native-client/images/menu-icon.png" /> &gt; Tools &gt; JavaScript console).</p>
<h2 id="handling-progress-events">Handling progress events</h2>
<p>You should add event listeners in a <code>&lt;script&gt;</code> element to listen for these
events before the <code>&lt;embed&gt;</code> element is parsed. For example, the following code
adds a listener for the <code>load</code> event to a parent <code>&lt;div&gt;</code> element that also
contains the Native Client <code>&lt;embed&gt;</code> element. First, the listener is
attached. Then, when the listener <code>&lt;div&gt;</code> receives the <code>load</code> event, the
JavaScript <code>moduleDidLoad()</code> function is called. The following code is
excerpted from the example in <code>getting_started/part1/</code>:</p>
<pre class="prettyprint">
&lt;!--
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 &lt;embed&gt; element is wrapped inside a &lt;div&gt;, 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 &lt;embed&gt; 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.
--&gt;
&lt;div id=&quot;listener&quot;&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var listener = document.getElementById('listener');
listener.addEventListener('load', moduleDidLoad, true);
listener.addEventListener('message', handleMessage, true);
&lt;/script&gt;
&lt;embed id=&quot;hello_tutorial&quot;
width=0 height=0
src=&quot;hello_tutorial.nmf&quot;
type=&quot;application/x-pnacl&quot; /&gt;
&lt;/div&gt;
</pre>
<p>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 <code>&lt;body&gt;</code> element) to handle events
from inner elements. For more information, see the W3 specifications for <a class="reference external" href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture">event
flow capture</a> and
<a class="reference external" href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">event listener registration</a>.</p>
<h2 id="displaying-load-status">Displaying load status</h2>
<p>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 <code>progress</code>
event is triggered the <code>moduleLoadProgress</code> function is called. This function
uses the <code>lengthComputable</code>, <code>loaded</code>, and <code>total</code> attributes (described
in the proposed W3C <a class="reference external" href="http://www.w3.org/TR/progress-events/">Progress Events</a>
standard) of the event to calculate the percentage of the module that has
loaded.</p>
<pre class="prettyprint">
function moduleLoadProgress(event) {
var loadPercent = 0.0;
var loadPercentString;
if (event.lengthComputable &amp;&amp; event.total &gt; 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...');
}
}
</pre>
<h2 id="the-lasterror-attribute">The <code>lastError</code> attribute</h2>
<p>The <code>&lt;embed&gt;</code> element has a <code>lastError</code> attribute that is set to an
informative string whenever a load failure (an <code>error</code> or <code>abort</code> event)
occurs.</p>
<p>The following code adds an event listener before the <code>&lt;embed&gt;</code> element to
capture and handle an error in loading the Native Client module. The
<code>handleError()</code> function listens for an <code>error</code> event. When an error occurs,
this function prints the contents of the <code>lastError</code> attribute
(<code>embed_element.lastError</code>) as an alert.</p>
<pre class="prettyprint">
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);
}
</pre>
<h2 id="the-readystate-attribute">The <code>readyState</code> attribute</h2>
<p>You can use the <code>readyState</code> attribute to monitor the loading process. This
attribute is particularly useful if you don&#8217;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 <code>readyState</code> progresses as follows
for a successful load:</p>
<table border="1" class="docutils">
<colgroup>
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Event</th>
<th class="head"><code>readyState</code> value</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>(before any events)</td>
<td><code>undefined</code></td>
</tr>
<tr class="row-odd"><td><code>loadstart</code></td>
<td>1</td>
</tr>
<tr class="row-even"><td><code>progress</code></td>
<td>3</td>
</tr>
<tr class="row-odd"><td><code>load</code></td>
<td>4</td>
</tr>
<tr class="row-even"><td><code>loadend</code></td>
<td>4</td>
</tr>
</tbody>
</table>
<p>The following code demonstrates how to monitor the loading process using the
<code>readyState</code> attribute. As before, the script that adds the event listeners
precedes the <code>&lt;embed&gt;</code> element so that the event listeners are in place before
the progress events are generated.</p>
<pre class="prettyprint">
&lt;html&gt;
...
&lt;body id=&quot;body&quot;&gt;
&lt;div id=&quot;status_div&quot;&gt;
&lt;/div&gt;
&lt;div id=&quot;listener_div&quot;&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var stat = document.getElementById('status_div');
function handleEvent(e) {
var embed_element = document.getElementById('my_embed');
stat.innerHTML +=
'&lt;br&gt;' + 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);
&lt;/script&gt;
&lt;embed
name=&quot;naclModule&quot;
id=&quot;my_embed&quot;
width=0 height=0
src=&quot;my_example.nmf&quot;
type=&quot;application/x-pnacl&quot; /&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<h2 id="the-exitstatus-attribute">The <code>exitStatus</code> attribute</h2>
<p>This read-only attribute is set if the application calls <code>exit(n)</code>,
<code>abort()</code>, or crashes. Since NaCl modules are event handlers, there is no
need to call <code>exit(n)</code> in normal execution. If the module does exit or
crash, the <code>crash</code> progress event is issued and the <code>exitStatus</code> attribute
will contain the numeric value of the exit status:</p>
<ul class="small-gap">
<li>In the case of explicit calls to <code>exit(n)</code>, the numeric value will be
<code>n</code> (between 0 and 255).</li>
<li>In the case of crashes and calls to <code>abort()</code>, 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 <code>exitStatus</code> value being stable in these cases, but the value
may nevertheless be useful for temporary debugging.</li>
</ul>
</section>
{{/partials.standard_nacl_api}}