16

We develop an application in an embedded environment. It is a high level computing environment with a complete webbrowser on top of a busybox Linux system. The only exception is that the system has a limited amount of system memory.

Our application is built in JavaScript and runs inside a Webkit based webbrowser and consists of a lot of javascript modules that are loaded in sequence (Which is not very efficient).

Some modules provide common functionality that is used by several modules. We are in the process of converting our current javascript loader with requirejs, but there is one specific need we have to address first.

Is it possible to unload a module when it has been loaded using requirejs? Assume that we dynamically loads a module using :

require(["somemodule.js"], function(m) { m.run(); } );

That works well for loading and running 'somemodule' and also resolving all dependencies for 'somemodule' and the requirejs framework will store a reference to 'somemodule' for future requests.

If we at some point need to reclaim memory, e.g to be able to load and run an infinite number of modules, we have to start removing some of them after some time. Is that possible with requirejs without altering the internal implementation?

Has anyone dealt with this kind of problem before? Most single page JS apps runs in a webbrowser on a desktop PC where memory usage usually is not a major concern.

2 Answers 2

17

RequireJS does not have a built-in unload feature, but it could be added perhaps as an additional part you could build into it. If you would like to have that feature, feel free to propose it in the mailing list or as a GitHub issue.

If you wanted to experiment to see if it helps your situation, what you need to do is the following:

1) Remove the defined module from the RequireJS module cache. If you are not using the multiversion support, you can do something like:

var context = require.s.contexts['_'];
delete context.defined[moduleName];
delete context.specified[moduleName];
delete context.loaded[moduleName];

2) Then you can try removing the script tag to see if that helps:

var scripts = document.getElementsByTagName('script');
for (var i = scripts.length - 1; i >= 0; i--) {
    var script = scripts[i];
    if (script.getAttribute('data-requiremodule') === moduleName) {
        script.parentNode.removeChild(script);
        break;
    }
}

Note that the module may not be garbage collected if another module holds on to it via the closure function(){} that defines that other module. That other module would need to be removed too.

You can try to limit that impact by not passing in the module as a function argument, but just use require("somemodule") inside the function definition whenever you want to get a hold of dependent modules, and not holding on to that require return value for too long.

Also, in your example above, for modules that use require.def to define themselves, it should look like this (without the .js suffix):

require(["somemodule"], function(m) { m.run(); } );
6
  • Thanks, I'll get back when I have tested it more. We still use our own script loader but will convert to requirejs, there are some refactoring ahead since the app currently uses a global namespace. I noticed in the source for requirejs that the onScriptLoad does not remove the scriptTag, but you recommend doing that in your answer above. Is it for performance reasons the scriptTag is kept in the DOM tree in requirejs? E.g since scriptag removal would add some extra processing in the loader. Our preloader always remove the scriptTag in the onload callback to preserve memory.
    – Ernelli
    Commented Jul 4, 2010 at 14:01
  • I do not remove the script tag to make debugging easier (did my script really load? Where from?) and also trying to keep down the size of the code of the loader. I figured there would not be much savings particularly over a page that had the script tags inlined in the HTML. However, I will make a note to test if it makes a difference to remove it, and it works across browsers. You indicate it does make a difference, maybe I should provide an option to do it. Any info on how you validate the memory savings is appreciated.
    – jrburke
    Commented Jul 5, 2010 at 4:35
  • 2
    The browser we use in our embedded system (an IPTV settop box) is based on Webkit. Even when the scripttags are removed from the document, the origins of exceptions etc are correctly labeled. I do have to make some more tests to see how much scriptTag removal affects the memory usage. Even when scriptTags are removed, the JS engine are able to re-create the source code for a given function (Although without comments). We do all of our memory profiling based on monitoring the amount of free memory in the system.
    – Ernelli
    Commented Jul 5, 2010 at 8:06
  • And next you'll have to define a virtual destructor for each module :) Commented Jul 19, 2012 at 12:36
  • i also face similar situation where i load google map for my single page app. I would really love to unload google and all its stuff to apreciate memory. Is there any development on latest requirejs?
    – Muhaimin
    Commented Apr 28, 2014 at 4:01
2

Try this: require.undef(moduleName)

1
  • 2
    from the requirejs documentation on undef: "[...]However, it will not remove the module from other modules that are already defined and got a handle on that module as a dependency when they executed. So it is really only useful to use in error situations when no other modules have gotten a handle on a module value"
    – Steen
    Commented Jun 27, 2013 at 20:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.