Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically load JavaScript AND monitor download progress

High-level view: I am using Emscripten in order to convert various legacy C/C++ codebases to optimized JavaScript so that a modern, browser-based userbase can easily make use of their functionality. So far, so good. However, Emscripten-transpiled JS can be a bit bulky, even after compressed for network delivery.

In order to improve user experience, I want to download this giant JS chunk after the main page has loaded, AND I want to monitor the download progress to display in the page UI. I know of 2 approaches for dynamic loading, and I am running into shortcomings with both:

  1. The first approach is to create a script tag (either embedded in the HTML page or dynamically generated by JS). The onload event fires when the file is downloaded and ready to run. The problem with this approach is that I can't find a way to monitor download progress. The script object does have an onprogress event but it doesn't seem to do anything (tested in Chrome).
  2. Use an XMLHTTPRequest (XHR) object to dynamically request the JS resource. This works well and fires the expected download progress events. However, running JS eval() on the downloaded data doesn't have the correct effect (the expected functions don't show up in the JS namespace).

Performing eval()'s of simpler JS-bearing strings has the expected result, so I'm wondering if there's some special trick to running eval() on Emscripten-compiled code.

Instead, I have implemented a hybrid solution combining approaches 1 and 2 above: the XHR performs the initial load and throws away the data. Then, the page creates a script element to load the same JS file, which is now in the browser's cache and loads instantly. But this is obviously a hack and I can't help but think that there must be a cleaner solution.

like image 312
Multimedia Mike Avatar asked Nov 22 '15 19:11

Multimedia Mike


1 Answers

Instead of throwing away the data, set a data to script tag.

var xhr = new XMLHttpRequest;
var tag = document.createElement("script");
xhr.open("GET", "foo.js", true);
xhr.onload = function (e) {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      tag.text = xhr.response;
      document.head.appendChild(tag);
    } else {
      alert("error");
      console.error(xhr.response);
    }
  }
};
xhr.onprogress = function (e) {
  Module.setStatus('Loading JavaScript: ' + (100 * e.loaded / + e.total) + '%');
};
xhr.send();
like image 176
zakki Avatar answered Oct 13 '22 12:10

zakki