Javascript 同步document.createElement(“脚本”)

Javascript 同步document.createElement(“脚本”),javascript,dom,synchronous,Javascript,Dom,Synchronous,是否可以同步调用.js文件,然后立即使用它 <script type="text/javascript"> var head = document.getElementsByTagName('head').item(0); var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('

是否可以同步调用
.js
文件,然后立即使用它

<script type="text/javascript">
    var head = document.getElementsByTagName('head').item(0);
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', 'http://mysite/my.js');
    head.appendChild(script);

    myFunction(); // Fails because it hasn't loaded from my.js yet.

    window.onload = function() {
        // Works most of the time but not all of the time.
        // Especially if my.js injects another script that contains myFunction().
        myFunction();
    };
</script>

我只是不想太了解内部结构,只想说,“我希望使用这个模块,现在我将使用其中的一些代码。”

这看起来像是动态脚本加载的一个不错的概述:

您可以使用“onload”处理程序创建
元素,当浏览器加载并评估脚本时,将调用该处理程序

var script = document.createElement('script');
script.onload = function() {
  alert("Script loaded and ready");
};
script.src = "http://whatever.com/the/script.js";
document.getElementsByTagName('head')[0].appendChild(script);
你不能同时做

编辑-有人指出,与表单一样,IE不会在加载/评估的
标记上触发“加载”事件。因此,我认为接下来要做的事情是使用XMLHttpRequest获取脚本,然后自己执行
eval()。(或者,我想,将文本填充到您添加的
标记中;
eval()
的执行环境受本地范围的影响,因此它不一定会执行您希望它执行的操作。)

编辑-从2013年初开始,我强烈建议寻找一个更强大的脚本加载工具,如。有很多特殊情况需要担心。对于非常简单的情况,现在内置了

异步编程稍微复杂一些,因为 发出请求的方法封装在函数中,而不是遵循请求语句但是用户体验的实时行为
可以显著地 更好,因为他们不会看到服务器或网络运行缓慢导致故障 使浏览器看起来好像崩溃了一样同步编程是不礼貌的 和不应在人们使用的应用程序中使用

道格拉斯·克罗克福德

好的,扣上你的座位,因为这将是一次颠簸的旅程。越来越多的人询问如何通过javascript动态加载脚本,这似乎是一个热门话题

它如此流行的主要原因是:

  • 客户端模块化
  • 更容易的依赖关系管理
  • 错误处理
  • 性能优势
关于模块化
:很明显,管理客户端依赖关系应该在客户端正确处理。如果需要某个对象、模块或库,我们只需请求并动态加载它

错误处理:如果资源失败,我们仍然有机会仅阻止依赖于受影响脚本的部分,或者甚至可以延迟再试一次

性能已经成为网站之间的竞争优势,它现在是搜索排名的一个因素。动态脚本可以模拟异步行为,而不是浏览器处理脚本的默认阻塞方式脚本块其他资源,脚本块进一步解析HTML文档,脚本块UI。现在,通过使用动态脚本标记及其跨浏览器的替代方案,您可以执行真正的异步请求,并仅在相关代码可用时执行它们。您的脚本将与其他资源并行加载,渲染将完美无缺

有些人坚持使用同步脚本的原因是他们已经习惯了。他们认为这是默认的方式,更简单的方式,有些人甚至认为这是唯一的方式

但是,当需要就应用程序的设计做出决定时,我们唯一应该关心的是最终用户体验。在这方面,我们是无法击败的。用户立即得到响应(或说承诺),承诺总比没有好。一块空白的屏幕吓人。开发人员不应该懒得提高感知性能

最后是关于肮脏的一面。要使其跨浏览器工作,您应该做什么:

  • 学会异步思考
  • 将代码组织为模块化
  • 组织代码以很好地处理错误和边缘情况
  • 逐步增强
  • 始终注意适当数量的反馈

  • 这并不漂亮,但很管用:

    <script type="text/javascript">
      document.write('<script type="text/javascript" src="other.js"></script>');
    </script>
    
    <script type="text/javascript">
      functionFromOther();
    </script>
    
    与Pointy一样,也可以创建节点,但仅在FF中。您无法保证脚本在其他浏览器中何时准备就绪


    作为一个XML纯粹主义者,我真的很讨厌这一点。但它确实可以预见。您可以轻松地包装那些难看的
    document.write()
    s,这样您就不必查看它们了。您甚至可以进行测试,创建一个节点并附加它,然后返回到
    document.write()

    具有讽刺意味的是,我拥有您想要的东西,但想要更接近您拥有的东西

    我以动态和异步方式加载东西,但是使用类似这样的
    load
    回调(使用dojo和XMLHtpRequest)

    有关更详细的说明,请参阅


    问题是代码在某个地方被赋值,如果您的代码有任何错误,
    console.error(errorMessage)语句将指示
    eval()
    所在的行,而不是实际错误。这是一个非常大的问题,实际上我正试图转换回
    语句(请参阅。

    这已经太晚了,但对于以后任何想这样做的人,您可以使用以下内容:

    function require(file,callback){
        var head=document.getElementsByTagName("head")[0];
        var script=document.createElement('script');
        script.src=file;
        script.type='text/javascript';
        //real browsers
        script.onload=callback;
        //Internet explorer
        script.onreadystatechange = function() {
            if (this.readyState == 'complete') {
                callback();
            }
        }
        head.appendChild(script);
    }
    

    不久前我写了一篇关于它的短文

    我习惯于在我的网站上有多个相互依赖的.js文件。为了加载它们并确保以正确的顺序计算依赖关系,我编写了一个函数,加载所有文件,然后在收到所有文件后,
    eval()
    它们。主要缺点是,由于这不会
    <script type="text/javascript">
      document.write('<script type="text/javascript" src="other.js"></script>');
      window.onload = function() {
        functionFromOther();
      };
    </script>
    
    <script type="text/javascript">
      document.write('<script type="text/javascript" src="other.js"></script>');
      functionFromOther(); // Error
    </script>
    
      dojo.xhrGet({
        url: 'getCode.php',
        handleAs: "javascript",
        content : {
        module : 'my.js'
      },
      load: function() {
        myFunc1('blarg');
      },
      error: function(errorMessage) {
        console.error(errorMessage);
      }
    });
    
    function require(file,callback){
        var head=document.getElementsByTagName("head")[0];
        var script=document.createElement('script');
        script.src=file;
        script.type='text/javascript';
        //real browsers
        script.onload=callback;
        //Internet explorer
        script.onreadystatechange = function() {
            if (this.readyState == 'complete') {
                callback();
            }
        }
        head.appendChild(script);
    }
    
    function xhrs(reqs) {
      var requests = [] , count = [] , callback ;
    
      callback = function (r,c,i) {
        return function () {
          if  ( this.readyState == 4 ) {
            if (this.status != 200 ) {
              r[i]['resp']="" ;
            } 
            else {
              r[i]['resp']= this.responseText ;
            }
            c[0] = c[0] - 1 ;
            if ( c[0] == 0 ) {
              for ( var j = 0 ; j < r.length ; j++ ) {
                eval(r[j]['resp']) ;
              }
            }
          }
        }
      } ;
      if ( Object.prototype.toString.call( reqs ) === '[object Array]' ) {
        requests.length = reqs.length ;
      }
      else {
        requests.length = 1 ;
        reqs = [].concat(reqs);
      }
      count[0] = requests.length ;
      for ( var i = 0 ; i < requests.length ; i++ ) {
        requests[i] = {} ;
        requests[i]['xhr'] = new XMLHttpRequest () ;
        requests[i]['xhr'].open('GET', reqs[i]) ;
        requests[i]['xhr'].onreadystatechange = callback(requests,count,i) ;
        requests[i]['xhr'].send(null);
      }
    }
    
    xhrs( [
           root + '/global.js' ,
           window.location.href + 'config.js' ,
           root + '/js/lib/details.polyfill.min.js',
           root + '/js/scripts/address.js' ,
           root + '/js/scripts/tableofcontents.js' 
    ]) ;
    
    //Code User TODO: you must create and set your own 'noEval' variable
    
    require = function require(inFileName)
    {
        var aRequest
            ,aScript
            ,aScriptSource
            ;
    
        //setup the full relative filename
        inFileName = 
            window.location.protocol + '//'
            + window.location.host + '/'
            + inFileName;
    
        //synchronously get the code
        aRequest = new XMLHttpRequest();
        aRequest.open('GET', inFileName, false);
        aRequest.send();
    
        //set the returned script text while adding special comment to auto include in debugger source listing:
        aScriptSource = aRequest.responseText + '\n////# sourceURL=' + inFileName + '\n';
    
        if(noEval)//<== **TODO: Provide + set condition variable yourself!!!!**
        {
            //create a dom element to hold the code
            aScript = document.createElement('script');
            aScript.type = 'text/javascript';
    
            //set the script tag text, including the debugger id at the end!!
            aScript.text = aScriptSource;
    
            //append the code to the dom
            document.getElementsByTagName('body')[0].appendChild(aScript);
        }
        else
        {
            eval(aScriptSource);
        }
    };
    
      var script = document.createElement('script');
      script.src = 'http://' + location.hostname + '/module';
      script.addEventListener('load', postLoadFunction);
      document.head.appendChild(script);
    
      function postLoadFunction() {
         // add module dependent code here
      }      
    
    function include(file){
    return new Promise(function(resolve, reject){
            var script = document.createElement('script');
            script.src = file;
            script.type ='text/javascript';
            script.defer = true;
            document.getElementsByTagName('head').item(0).appendChild(script);
    
            script.onload = function(){
            resolve()
            }
            script.onerror = function(){
              reject()
            }
          })
    
     /*I HAVE MODIFIED THIS TO  BE PROMISE-BASED 
       HOW TO USE THIS FUNCTION 
    
      include('js/somefile.js').then(function(){
      console.log('loaded');
      },function(){
      console.log('not loaded');
      })
      */
    }
    
    // This is a modern JS dependency fetcher - a "webpack" for the browser
    const addDependentScripts = async function( scriptsToAdd ) {
    
      // Create an empty script element
      const s=document.createElement('script')
    
      // Fetch each script in turn, waiting until the source has arrived
      // before continuing to fetch the next.
      for ( var i = 0; i < scriptsToAdd.length; i++ ) {
        let r = await fetch( scriptsToAdd[i] )
    
        // Here we append the incoming javascript text to our script element.
        s.text += await r.text()
      }
    
      // Finally, add our new script element to the page. It's
      // during this operation that the new bundle of JS code 'goes live'.
      document.querySelector('body').appendChild(s)
    }
    
    // call our browser "webpack" bundler
    addDependentScripts( [
      'https://code.jquery.com/jquery-3.5.1.slim.min.js',
      'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js'
    ] )