Dynamically loading JavaScript synchronously

后端 未结 18 2171
小蘑菇
小蘑菇 2020-11-27 13:55

I\'m using the module pattern, one of the things I want to do is dynamically include an external JavaScript file, execute the file, and then use the functions/variables in t

相关标签:
18条回答
  • 2020-11-27 14:33

    If you need to load an arbitrary number of scripts and only proceed when the last one is done, and you cannot use XHR (e.g. due to CORS limitations) you can do the following. It is not synchronous, but does allow a callback to occur exactly when the last file is done loading:

    // Load <script> elements for all uris
    // Invoke the whenDone callback function after the last URI has loaded
    function loadScripts(uris,whenDone){
      if (!uris.length) whenDone && whenDone();
      else{
        for (var wait=[],i=uris.length;i--;){
          var tag  = document.createElement('script');
          tag.type = 'text/javascript';
          tag.src  = uris[i];
          if (whenDone){
            wait.push(tag)
            tag.onload = maybeDone; 
            tag.onreadystatechange = maybeDone; // For IE8-
          }
          document.body.appendChild(tag);
        }
      }
      function maybeDone(){
        if (this.readyState===undefined || this.readyState==='complete'){
          // Pull the tags out based on the actual element in case IE ever
          // intermingles the onload and onreadystatechange handlers for the same
          // script block before notifying for another one.
          for (var i=wait.length;i--;) if (wait[i]==this) wait.splice(i,1);
          if (!wait.length) whenDone();
        }
      }
    }
    

    Edit: Updated to work with IE7, IE8, and IE9 (in quirks mode). These IE versions do not fire an onload event, but do for onreadystatechange. IE9 in standards mode fires both (with onreadystatechange for all scripts firing before onload for any).

    Based on this page there may be a small chance that old versions of IE will never send an onreadystatechange event with readyState=='complete'; if this is the case (I could not reproduce this problem) then the above script will fail and your callback will never be invoked.

    0 讨论(0)
  • 2020-11-27 14:33

    My strategy, classic example when load jQuery UI, i hope this can help you

    ( function( tools, libs ){
    	
        // Iterator
        var require = function( scripts, onEnd ){
            
            onEnd = onEnd || function(){};
            
            if( !scripts || scripts.length < 1 )return onEnd();
            
            var src    = scripts.splice( 0, 1),
                script = document.createElement( "script" );
            
            script.setAttribute( "src", src );
            
            tools.addEvent( "load", script, function(){
                
                require( scripts, onEnd );
                
            } );
            
            document.getElementsByTagName( "head" )[ 0 ].appendChild( script );
            
        };
        
        // Install all scripts with a copy of scripts
        require( libs.slice(), function(){
        
            alert( "Enjoy :)" );
        
        } );
        
        // Timeout information
        var ti = setTimeout( function(){
            
            if( !window.jQuery || !window.jQuery.ui )alert( "Timeout !" );
            
            clearTimeout( ti );
            
        }, 5000 );
    
    } )(
    
        { // Tools
        
            addEvent : function( evnt, elem, func ){
            
                try{
    
                    if( elem.addEventListener ){
    
                        elem.addEventListener( evnt, func, false );
    
                    }else if( elem.attachEvent ){
    
                         var r = elem.attachEvent( "on" + evnt, func );
    
                    }
    
                    return true;
    
                }catch( e ){
    
                    return false;
    
                }		    
    
            }
        
        },
        [ // Scripts
        
            "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js",
            "https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"
            
        ]
    
    );

    0 讨论(0)
  • 2020-11-27 14:35

    I use jquery load method applied to div element. something like

    <div id="js">
    <!-- script will be inserted here --> 
    </div>
    
    ...
    
    $("#js").load("path", function() {  alert("callback!" });
    

    You can load scripts several times and each time one script will completely replace the one loaded earlier

    0 讨论(0)
  • 2020-11-27 14:37
    var xhrObj = new XMLHttpRequest();
    xhrObj.open('GET', '/filename.js', false);
    xhrObj.send(null);
    eval(xhrObj.responseText);
    

    If this is a cross-domain request, it will not work. In that case you have to upload the requested file to your server, or make a mirror php that outputs it, and require that php.

    With jquery (works with cross-domain request too):

    $.getScript('/filename.js',callbackFunction);
    

    callbackFunction will be called synchronously.

    For loading more scripts see this thread.

    0 讨论(0)
  • 2020-11-27 14:37

    I know this is an old question, but maybe someone else read this and find it useful ! Just created a new components uses ES6 to load scripts dynamically in synchronous way. The Project details and source code are on GitHub https://github.com/amgadfahmi/scripty

    0 讨论(0)
  • 2020-11-27 14:38

    When using Angular you can take advantage of the fact that every Provider is instantiated before other services are instantiated. You can combine this fact with using xhr and the eval() as mentioned by @Neil. The code would be following:

    app.provider('SomeScriptSyncLoader', function() {
    
        var resourceUrl =  'http://some/script.js';
        var dummy = {};
    
        this.$get = function() {
    
            var q = jQuery.ajax({
                type: 'GET', url: resourceUrl, cache: false, async: false
            });
    
            if (q.status === 200) {
                eval(q.responseText); // execute some script synchronously as inline script - eval forces sync processing
            }
            return dummy;
        };
    });
    

    To force the Provider to be inialized you need to inject it in at least one other directive/service. Preferably this would be the service which takes advantage of the code loaded by script.

    app.directive('myDirective', ['SomeScriptSyncLoader', function(someScriptSyncLoader) {
    
    return {
        restrict: 'E',
        link: function(scope, element, attrs) {
            // some ode
        },
        template: "this is my template"
       };
    }]);
    
    0 讨论(0)
提交回复
热议问题