requirejs race condition - how to block until prev

2019-07-09 01:24发布

问题:

common_tempaltes file is not a requirejs file - rather a file that defines a global variable.

common_templates needs hogan. they both are requested more or less at the same time, but race condition is in affect. common_templates sometimes wins so the code fails with "hogan not loaded yet".

require(['module1', 'hogan', 'common_templates'], function(Module){
    Module.do_stuff() // this module also requires hogan and common_templates to be loaded
});

other than nested require, is there a built in way to tell require to block until hogan is fully downloaded?

nested:

require(['hogan'], function(Fn, Ui){
    require(['common_templates'], function(){
        require(['module1'], function(Module){
            Module.do_stuff();
        });
    });
});

This approach seems a bit hacky. is there a built in way to work around these race conditions?

回答1:

If common_templates is not an AMD module (doesn't contain a define([deps]) call), then you need to configure it as a shim:

require.config({
  shims: {
     common_templates: {
      deps: ["hogan"]
     }
  } 
});

Now, require(['module1', 'hogan', 'common_templates']) and require(['module1', 'common_templates']) should work.



回答2:

I had this exact same issue. I needed to essentially 'block' my program flow to ensure that an initial list of dependencies were loaded before a second list of dependencies, and then finally my main application code. Here is how I solved it. This is the Require.js call I made in my index.html file:

<script src="/js/lib/require_2.1.22.js"></script>
<script>
    //debugger;
    //Load common code that includes config, then load the app
    //logic for this page. Do the requirejs calls here instead of
    //a separate file so after a build there are only 2 HTTP
    //requests instead of three.
    requirejs(['/js/common_libs.js'], function (common) {
        //debugger;
        //Ensure the the AdminLTE code and its dependencies get loaded prior to loading the Backbone App.
        requirejs(['/js/lib/adminlte.js'], function (common) {
            //debugger;
            //The main file for the Backbone.js application.
            requirejs(['/js/app/main_app.js']);
        });
    });
</script>

The common_libs.js file contains the requirejs.config({shim:...}) stuff. The adminlte.js library does it's own dependency checking and will complain on the console if it does not detect it's dependencies. My problem was that it was getting loaded asynchronously with its dependencies and was causing a race condition.

I was able to wrap the existing code in adminlte.js like this:

//My experiments with Require.js to prevent race conditions.
define([
    'jQuery-2.1.4.min',
    'bootstrap.3.3.6',
    'jquery.slimscroll.min'
], function($, Bootstrap, SlimScroll ) {

  //Existing code goes here
  ...

  //I knew to return this value by looking at the AdminLTE code. Your mileage may vary.
  return $.AdminLTE;
});

That allowed me to load this library separately with its dependencies. The code in adminlte.js is only execute after its dependencies are loaded. Then, and only after that is complete, will main_app.js be loaded, along with its dependencies.

Structuring your code this way allows you to explicitly load your dependencies in batches.


Editing for clarity:

The dependencies are loaded in stages. To clarify the example above:

In the first stage jQuery, Boostrap, and the SlimScroll library are loaded, then the adminlte.js file is execute.

In the second stage, all other dependencies are loaded, then the main_app.js file is executed. main_app.js will have its own defined([], ...) function that calls out the rest of the dependencies it will need loaded.

This is much more efficient than writing a nested require() call for each dependency. And, as far as I can tell from the requirejs.org website, this is the 'proper' way to load serial dependencies.


Coding Update: I also had to wrap the code in the jquery.slimscroll library inside a define() statement in order to explicitly call out the that this library depends on jQuery. Otherwise it was setting up another chance at a race condition.



回答3:

This does not make sense, you said "common_templates requires hogan" but if common_templates requires hogan then hogan will already be loaded when the common_templates code starts.

Make sure common_templates.js is defined like this:

define(['hogan'], function(){
    //common_templates suff here
});