diff options
| author | Ian Jackson <ijackson@chiark.greenend.org.uk> | 2021-04-22 19:20:32 +0100 |
|---|---|---|
| committer | Simon Tatham <anakin@pobox.com> | 2021-04-22 21:22:48 +0100 |
| commit | 77866e1335bd1ea7189f11c19ff2947be17aa517 (patch) | |
| tree | 1f5d0dd32cc71e20d67c44033b23e38726af64d7 /emccpre.js | |
| parent | 56ef86f92b77412bfe27d7206d25b323475e71fe (diff) | |
| download | puzzles-77866e1335bd1ea7189f11c19ff2947be17aa517.zip puzzles-77866e1335bd1ea7189f11c19ff2947be17aa517.tar.gz puzzles-77866e1335bd1ea7189f11c19ff2947be17aa517.tar.bz2 puzzles-77866e1335bd1ea7189f11c19ff2947be17aa517.tar.xz | |
wasm/js/emscripten: Fix page loading race
Using a stunt webserver which artificially introduces a 3s delay just
before the last line of the HTML output, I have reproduced a
uwer-reported loading/startup race bug:
Previously the wasm loading was started by the <script> element,
synchronously. If the wasm loading is fast, and finishes before the
HTML loading, the onRuntimeInitialized event may occur before
initPuzzles. But initPuzzles sets up the event handler.
Fix this bug, and introduce a new comment containing an argument for
the correctness of the new approach.
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Diffstat (limited to 'emccpre.js')
| -rw-r--r-- | emccpre.js | 45 |
1 files changed, 45 insertions, 0 deletions
@@ -35,6 +35,51 @@ var update_xmin, update_xmax, update_ymin, update_ymax; // our own init stuff first), and that when main() returns nothing // will get cleaned up so we remain able to call the puzzle's various // callbacks. +// +// +// Page loading order: +// +// 1. The browser starts reading *.html (which comes from jspage.pl) +// 2. It finds the <script> tag. This is marked defer, so the +// browser will start fetching and parsing it, but not execute it +// until the page has loaded. +// +// Now the browser is loading *.html and *.js in parallel. The +// html is rendered as we go, and the js is deferred. +// +// 3. The HTML finishes loading. The browser is about to fire the +// `DOMContentLoaded` event (ie `onload`) but before that, it +// actually runs the deferred JS. THis consists of +// +// (i) emccpre.js (this file). This sets up various JS variables +// including the emscripten Module object. +// +// (ii) emscripten's JS. This starts the WASM loading. +// +// (iii) emccpost.js. This calls initPuzzle, which is defined here +// in this file. initPuzzle: +// +// (a) finds various DOM elements and bind them to variables, +// which depend on the HTML having loaded (it has). +// +// (b) makes various `cwrap` calls into the emscripten module to +// set up hooks; this depends on the emscripten JS having been +// loaded (it has). +// +// (c) Makes the call to emscripten's +// Module.onRuntimeInitialized, which sets the callback for when +// the WASM has finished loading and initialising. This has to +// come before the WASM finishes loading, or we'll miss the +// callback. We are executing synchronously here in the same JS +// file as started the WASM loading, so that is guaranteed. +// +// When this JS execution is complete, the browser fires the `onload` +// event. This is ignored. It continues loading the WASM. +// +// 4. The WASM loading and initialisation completes. The +// onRuntimeInitialised callback calls into emscripten-generated +// WASM to call the C `main`, to actually start the puzzle. + var Module = { 'noInitialRun': true, 'noExitRuntime': true |