blob: 8cf6869e45537a8bcf1c4853dc89072b96ec7541 [file] [log] [blame]
{{+bindTo:partials.standard_nacl_article}}
<b><font color="#cc0000">
NOTE:
Deprecation of the technologies described here has been announced
for platforms other than ChromeOS.<br/>
Please visit our
<a href="/native-client/migration">migration guide</a>
for details.
</font></b>
<hr/><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 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
<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>/pepper_&lt;version&gt;/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">Times
triggered</th>
<th class="head">When
triggered</th>
<th class="head">How you might
respond</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><dl class="first last docutils">
<dt><code>loadstart</code></dt>
<dd>Native Client has started to
load a Native Client module.</dd>
</dl>
</td>
<td>once</td>
<td>The
first
progress
event
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><dl class="first last docutils">
<dt><code>progress</code></dt>
<dd>Part of the module has been
loaded.</dd>
</dl>
</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><dl class="first last docutils">
<dt><code>error</code></dt>
<dd>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).</dd>
</dl>
</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><dl class="first last docutils">
<dt><code>abort</code></dt>
<dd>Loading of the NativeClient
module was aborted by the user.</dd>
</dl>
</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><dl class="first last docutils">
<dt><code>load</code></dt>
<dd>The Native Client module was
successfully loaded, and
execution was started.
(The module was initialized
successfully.)</dd>
</dl>
</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><dl class="first last docutils">
<dt><code>loadend</code></dt>
<dd>Loading of the Native Client
module has stopped. Load
succeeded (<code>load</code>), failed
(<code>error</code>), or was aborted
(<code>abort</code>).</dd>
</dl>
</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><dl class="first last docutils">
<dt><code>crash</code></dt>
<dd>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.</dd>
</dl>
</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_article}}