1 .. _devcycle-progress-events: 2 3 :template: standard_nacl_api 4 5 ############### 6 Progress Events 7 ############### 8 9 .. contents:: 10 :local: 11 :backlinks: none 12 :depth: 2 13 14 There are five types of events that developers can respond to in Native Client: 15 progress, message, view change, focus, and input events (each described in the 16 glossary below). This chapter describes how to monitor progress events (events 17 that occur during the loading and execution of a Native Client module). This 18 chapter assumes you are familiar with the material presented in the 19 :doc:`Technical Overview <../../overview>`. 20 21 .. Note:: 22 :class: note 23 24 The load_progress example illustrates progress event handling. You can find 25 this code in the ``/examples/tutorial/load_progress/`` directory in the Native 26 Client SDK download. 27 28 Module loading and progress events 29 ================================== 30 31 The Native Client runtime reports a set of state changes during the module 32 loading process by means of DOM progress events. This set of events is a direct 33 port of the proposed W3C `Progress Events 34 <http://www.w3.org/TR/progress-events/>`_ standard (except for the ``crash`` 35 event which is an extension of the W3C standard). The following table lists the 36 events types reported by the Native Client runtime: 37 38 +-------------+--------------------+-----------+---------------+---------------+ 39 | Event | Description | Number of | When event is | How you might | 40 | | | times | triggered | react to | 41 | | | triggered | | event | 42 +=============+====================+===========+===============+===============+ 43 |``loadstart``| Native Client has | once | This is the | Display a | 44 | | started to load a | | first | status | 45 | | Native Client | | progress | message, such | 46 | | module. | | event | as | 47 | | | | triggered | "Loading..." | 48 | | | | after the | | 49 | | | | Native Client | | 50 | | | | module is | | 51 | | | | instantiated | | 52 | | | | and | | 53 | | | | initialized. | | 54 +-------------+--------------------+-----------+---------------+---------------+ 55 |``progress`` | Part of the module | zero or | After | Display a | 56 | | has been loaded. | more | ``loadstart`` | progress bar. | 57 | | | | has been | | 58 | | | | dispatched. | | 59 +-------------+--------------------+-----------+---------------+---------------+ 60 |``error`` | The Native Client | zero or | After the | Inform user | 61 | | module failed to | once | last | that the | 62 | | start execution | | ``progress`` | application | 63 | | (includes any | | event has | failed to | 64 | | error before or | | been | load. | 65 | | during | | dispatched, | | 66 | | initialization of | | or after | | 67 | | the module). The | | ``loadstart`` | | 68 | | ``lastError`` | | if no | | 69 | | attribute | | ``progress`` | | 70 | | (mentioned later) | | event was | | 71 | | provides details | | dispatched. | | 72 | | on the error | | | | 73 | | (initialization | | | | 74 | | failed, sel_ldr | | | | 75 | | did not start, | | | | 76 | | and so on). | | | | 77 +-------------+--------------------+-----------+---------------+---------------+ 78 |``abort`` | Loading of the | zero or | After the | It's not | 79 | | Native Client | once | last | likely you | 80 | | module was | | ``progress`` | will want to | 81 | | aborted by the | | event has | respond to | 82 | | user. | | been | this event. | 83 | | | | dispatched, | | 84 | | | | or after | | 85 | | | | ``loadstart`` | | 86 | | | | if no | | 87 | | | | ``progress`` | | 88 | | | | event was | | 89 | | | | dispatched. | | 90 +-------------+--------------------+-----------+---------------+---------------+ 91 |``load`` | The Native Client | zero or | After the | Remove the | 92 | | module was | once | last | progress bar. | 93 | | successfully | | ``progress`` | | 94 | | loaded, and | | event has | | 95 | | execution was | | been | | 96 | | started. (The | | dispatched, | | 97 | | module was | | or after | | 98 | | initialized | | ``loadstart`` | | 99 | | successfully.) | | if no | | 100 | | | | ``progress`` | | 101 | | | | event was | | 102 | | | | dispatched. | | 103 +-------------+--------------------+-----------+---------------+---------------+ 104 |``loadend`` | Loading of the | once | After an | Indicate | 105 | | Native Client | | ``error``, | loading is | 106 | | module has | | ``abort``, or | over | 107 | | stopped. Load | | ``load`` | (regardless | 108 | | succeeded | | event was | of failure or | 109 | | (``load``), | | dispatched. | not). | 110 | | failed | | | | 111 | | (``error``), or | | | | 112 | | was aborted | | | | 113 | | (``abort``). | | | | 114 +-------------+--------------------+-----------+---------------+---------------+ 115 |``crash`` | The Native Client | zero or | After a | Notify user | 116 | | module is not | once | ``loadend``. | that the | 117 | | responding (died | | | module did | 118 | | on an | | | something | 119 | | ``assert()`` or | | | illegal. | 120 | | ``exit()``) after | | | | 121 | | a successful | | | | 122 | | load. This event | | | | 123 | | is unique to | | | | 124 | | Native Client and | | | | 125 | | is not part of | | | | 126 | | the W3C Progress | | | | 127 | | Events standard. | | | | 128 | | The ``exitStatus`` | | | | 129 | | attribute provides | | | | 130 | | the numeric exit | | | | 131 | | status value. | | | | 132 +-------------+--------------------+-----------+---------------+---------------+ 133 134 The sequence of events for a successful module load is as follows: 135 136 =============================== =============================== 137 Event is dispatched ... then this task is attempted 138 =============================== =============================== 139 ``loadstart`` load the manifest file 140 ``progress`` (first time) load the module 141 ``progress`` (subsequent times) 142 ``load`` start executing the module 143 ``loadend`` 144 =============================== =============================== 145 146 Errors that occur during loading are logged to the JavaScript console in Google 147 Chrome (select the menu icon |menu-icon| > Tools > JavaScript console). 148 149 .. |menu-icon| image:: /images/menu-icon.png 150 151 Handling progress events 152 ======================== 153 154 You should add event listeners in a ``<script>`` element to listen for these 155 events before the ``<embed>`` element is parsed. For example, the following code 156 adds a listener for the ``load`` event to a parent ``<div>`` element that also 157 contains the Native Client ``<embed>`` element. First, the listener is 158 attached. Then, when the listener ``<div>`` receives the ``load`` event, the 159 JavaScript ``moduleDidLoad()`` function is called. The following code is 160 excerpted from the example in ``getting_started/part1/``: 161 162 .. naclcode:: 163 164 <!-- 165 Load the published pexe. 166 Note: Since this module does not use any real-estate in the browser, its 167 width and height are set to 0. 168 169 Note: The <embed> element is wrapped inside a <div>, which has both a 'load' 170 and a 'message' event listener attached. This wrapping method is used 171 instead of attaching the event listeners directly to the <embed> element to 172 ensure that the listeners are active before the NaCl module 'load' event 173 fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or 174 pp::Instance.PostMessage() (in C++) from within the initialization code in 175 your module. 176 --> 177 <div id="listener"> 178 <script type="text/javascript"> 179 var listener = document.getElementById('listener'); 180 listener.addEventListener('load', moduleDidLoad, true); 181 listener.addEventListener('message', handleMessage, true); 182 </script> 183 184 <embed id="hello_tutorial" 185 width=0 height=0 186 src="hello_tutorial.nmf" 187 type="application/x-pnacl" /> 188 </div> 189 190 Event listeners can be added to any DOM object. Since listeners set at the 191 outermost scope capture events for their contained elements, you can set 192 listeners on outer elements (including the ``<body>`` element) to handle events 193 from inner elements. For more information, see the W3 specifications for `event 194 flow capture 195 <http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture>`_ and 196 `event listener registration 197 <http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration>`_. 198 199 Displaying load status 200 ====================== 201 202 One common response to progress events is to display the percentage of the 203 module that has been loaded. In the load_progress example, when the ``progress`` 204 event is triggered the ``moduleLoadProgress`` function is called. This function 205 uses the ``lengthComputable``, ``loaded``, and ``total`` attributes (described 206 in the proposed W3C `Progress Events <http://www.w3.org/TR/progress-events/>`_ 207 standard) of the event to calculate the percentage of the module that has 208 loaded. 209 210 .. naclcode:: 211 212 function moduleLoadProgress(event) { 213 var loadPercent = 0.0; 214 var loadPercentString; 215 if (event.lengthComputable && event.total > 0) { 216 loadPercent = event.loaded / event.total * 100.0; 217 loadPercentString = loadPercent + '%'; 218 common.logMessage('progress: ' + event.url + ' ' + loadPercentString + 219 ' (' + event.loaded + ' of ' + event.total + ' bytes)'); 220 } else { 221 // The total length is not yet known. 222 common.logMessage('progress: Computing...'); 223 } 224 } 225 226 The ``lastError`` attribute 227 =========================== 228 229 The ``<embed>`` element has a ``lastError`` attribute that is set to an 230 informative string whenever a load failure (an ``error`` or ``abort`` event) 231 occurs. 232 233 The following code adds an event listener before the ``<embed>`` element to 234 capture and handle an error in loading the Native Client module. The 235 ``handleError()`` function listens for an ``error`` event. When an error occurs, 236 this function prints the contents of the ``lastError`` attribute 237 (``embed_element.lastError``) as an alert. 238 239 .. naclcode:: 240 241 function domContentLoaded(name, tc, config, width, height) { 242 var listener = document.getElementById('listener'); 243 ... 244 listener.addEventListener('error', moduleLoadError, true); 245 ... 246 common.createNaClModule(name, tc, config, width, height); 247 } 248 249 function moduleLoadError() { 250 common.logMessage('error: ' + common.naclModule.lastError); 251 } 252 253 The ``readyState`` attribute 254 ============================ 255 256 You can use the ``readyState`` attribute to monitor the loading process. This 257 attribute is particularly useful if you don't care about the details of 258 individual progress events or when you want to poll for current load state 259 without registering listeners. The value of ``readyState`` progresses as follows 260 for a successful load: 261 262 =================== ==================== 263 Event ``readyState`` value 264 =================== ==================== 265 (before any events) ``undefined`` 266 ``loadstart`` 1 267 ``progress`` 3 268 ``load`` 4 269 ``loadend`` 4 270 =================== ==================== 271 272 The following code demonstrates how to monitor the loading process using the 273 ``readyState`` attribute. As before, the script that adds the event listeners 274 precedes the ``<embed>`` element so that the event listeners are in place before 275 the progress events are generated. 276 277 .. naclcode:: 278 279 <html> 280 ... 281 <body id="body"> 282 <div id="status_div"> 283 </div> 284 <div id="listener_div"> 285 <script type="text/javascript"> 286 var stat = document.getElementById('status_div'); 287 function handleEvent(e) { 288 var embed_element = document.getElementById('my_embed'); 289 stat.innerHTML += 290 '<br>' + e.type + ': readyState = ' + embed_element.readyState; 291 } 292 var listener_element = document.getElementById('listener_div'); 293 listener_element.addEventListener('loadstart', handleEvent, true); 294 listener_element.addEventListener('progress', handleEvent, true); 295 listener_element.addEventListener('load', handleEvent, true); 296 listener_element.addEventListener('loadend', handleEvent, true); 297 </script> 298 <embed 299 name="naclModule" 300 id="my_embed" 301 width=0 height=0 302 src="my_example.nmf" 303 type="application/x-pnacl" /> 304 </div> 305 </body> 306 </html> 307 308 The ``exitStatus`` attribute 309 ============================ 310 311 This read-only attribute is set if the application calls ``exit(n)``, 312 ``abort()``, or crashes. Since NaCl modules are event handlers, there is no 313 need to call ``exit(n)`` in normal execution. If the module does exit or 314 crash, the ``crash`` progress event is issued and the ``exitStatus`` attribute 315 will contain the numeric value of the exit status: 316 317 * In the case of explicit calls to ``exit(n)``, the numeric value will be 318 ``n`` (between 0 and 255). 319 * In the case of crashes and calls to ``abort()``, the numeric value will 320 be non-zero, but the exact value will depend on the chosen libc and the 321 target architecture, and may change in the future. Applications should not 322 rely on the ``exitStatus`` value being stable in these cases, but the value 323 may nevertheless be useful for temporary debugging. 324