异步加载脚本


125

我正在使用JQuery的几个插件,自定义窗口小部件和其他一些库。结果,我有几个.js和.css文件。我需要为网站创建一个加载器,因为加载需要一些时间。如果可以在导入所有内容之前显示加载程序,那就太好了:

<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/myFunctions.js"></script>
<link type="text/css" href="css/main.css" rel="stylesheet" />
... 
....
 etc

我找到了一些教程,这些教程使我能够异步导入JavaScript库。例如,我可以做类似的事情:

  (function () {
        var s = document.createElement('script');
        s.type = 'text/javascript';
        s.async = true;
        s.src = 'js/jquery-ui-1.8.16.custom.min.js';
        var x = document.getElementsByTagName('script')[0];
        x.parentNode.insertBefore(s, x);
    })();

由于某种原因,当我对所有文件执行相同操作时,页面将无法正常工作。我已经尝试了很长时间,试图找到问题所在,但我只是找不到。首先,我认为这可能是因为某些javascript函数依赖于其他javascript函数。但是当我完成下一个任务时,我使用超时功能以正确的顺序加载了它们,然后继续执行下一个任务,页面仍然表现得很奇怪。例如,我无法单击链接等...动画仍然可以工作..

无论如何

这就是我一直在想的...我认为浏览器具有缓存,这就是为什么第一次和第二次快速加载页面需要较长时间的原因。所以我想做的是用一个异步加载所有这些文件的页面替换index.html页面。当ajax完成加载后,所有这些文件都将重定向到我计划使用的页面。使用该页面时,加载时间不会太长,因为文件应该包含在浏览器的缓存中。在我的索引页面上(异步加载.js和.css文件的页面),我不在乎出现错误。我将只显示一个加载器,并在完成后重定向页面...

这个想法是一个好的选择吗?还是应该继续尝试实现异步方法?


编辑

我加载所有异步数据的方式如下:

importScripts();

function importScripts()
{
    //import: jquery-ui-1.8.16.custom.min.js
    getContent("js/jquery-1.6.2.min.js",function (code) {
                var s = document.createElement('script');
                s.type = 'text/javascript';
                //s.async = true;
                s.innerHTML=code;
                var x = document.getElementsByTagName('script')[0];
                x.parentNode.insertBefore(s, x);
                setTimeout(insertNext1,1);
            });


    //import: jquery-ui-1.8.16.custom.min.js
    function insertNext1()
    {
        getContent("js/jquery-ui-1.8.16.custom.min.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext2,1);
                });
    }

    //import: jquery-ui-1.8.16.custom.css
    function insertNext2()
    {

        getContent("css/custom-theme/jquery-ui-1.8.16.custom.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext3,1);
                });
    }

    //import: main.css
    function insertNext3()
    {

        getContent("css/main.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext4,1);
                });
    }

    //import: jquery.imgpreload.min.js
    function insertNext4()
    {
        getContent("js/farinspace/jquery.imgpreload.min.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext5,1);
                });
    }


    //import: marquee.js
    function insertNext5()
    {
        getContent("js/marquee.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext6,1);
                });
    }


    //import: marquee.css
    function insertNext6()
    {

        getContent("css/marquee.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext,1);
                });
    }



    function insertNext()
    {
        setTimeout(pageReadyMan,10);        
    }
}


// get the content of url and pass that content to specified function
function getContent( url, callBackFunction )
{
     // attempt to create the XMLHttpRequest and make the request
     try
     {
        var asyncRequest; // variable to hold XMLHttpRequest object
        asyncRequest = new XMLHttpRequest(); // create request object

        // register event handler
        asyncRequest.onreadystatechange = function(){
            stateChange(asyncRequest, callBackFunction);
        } 
        asyncRequest.open( 'GET', url, true ); // prepare the request
        asyncRequest.send( null ); // send the request
     } // end try
     catch ( exception )
     {
        alert( 'Request failed.' );
     } // end catch
} // end function getContent

// call function whith content when ready
function stateChange(asyncRequest, callBackFunction)
{
     if ( asyncRequest.readyState == 4 && asyncRequest.status == 200 )
     {
           callBackFunction(asyncRequest.responseText);
     } // end if
} // end function stateChange

而奇怪的是,所有样式的工作加上所有javascript函数。该页面由于某些原因被冻结...

Answers:


176

异步加载的几种解决方案:

//this function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
  var s,
      r,
      t;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentNode.insertBefore(s, t);
}

如果页面上已有jQuery,请使用:

$.getScript(url, successCallback)*

此外,有可能在文档加载完成之前就已经加载/执行了脚本,这意味着您需要等待document.ready事件才能绑定到元素。

在不查看代码的情况下,无法明确分辨出您的问题是什么。

最简单的解决方案是将所有脚本内联在页面底部,这样它们就不会在执行时阻止HTML内容的加载。它还避免了必须异步加载每个所需脚本的问题。

如果您有一个并非总是使用的特别花哨的交互功能,并且需要某种更大的脚本,那么避免在需要之前加载该特定脚本(延迟加载)可能会很有用。

* 加载的脚本$.getScript可能不会被缓存


对于可以使用现代功能(例如Promise对象)的任何人,该loadScript功能都变得更加简单:

function loadScript(src) {
    return new Promise(function (resolve, reject) {
        var s;
        s = document.createElement('script');
        s.src = src;
        s.onload = resolve;
        s.onerror = reject;
        document.head.appendChild(s);
    });
}

请注意,此版本不再接受callback参数,因为返回的Promise将处理回调。以前应该是loadScript(src, callback)现在loadScript(src).then(callback)

这具有能够检测和处理故障的额外好处,例如可以打电话给...

loadScript(cdnSource)
    .catch(loadScript.bind(null, localSource))
    .then(successCallback, failureCallback);

...并且它将优雅地处理CDN中断。


我将开始尝试。但是,如果我在将页面重定向到其他页面时将这些脚本加载到其他页面上,并且该页面恰好具有相同的脚本,则它们应该花时间加载。他们应该在缓存中吧?所以我不应该实施那种技术吗?
Tono Nam

1
我更改了子项并将其附加到head标记而不是body。..var x = document.getElementsByTagName('head')[0]; x.appendChild(s);
Tono Nam

1
@TonoNam,您可以使用document.head.appendChild,但是将脚本添加到<head>;中存在一些小问题。没有什么可以阻止脚本加载和执行。
zzzzBov

1
我不得不使用t.parentNode.insertBefore(与t.parent相反)。
Phil LaNasa

1
@MuhammadUmer,如果要在document.write加载文档之前使用编写其他脚本标记,则脚本将在加载页面时同步执行,并且不会单独包含任何异步回调行为。如果要创建脚本元素并将其添加到页面,则可以访问添加事件侦听器以异步触发。tl; dr:这取决于您如何使用JS加载脚本。
zzzzBov 2014年

33

HTML5的新“异步”属性应该可以解决问题。如果您关心IE,大多数浏览器也支持“ defer”。

异步-HTML

<script async src="siteScript.js" onload="myInit()"></script>

延迟-HTML

<script defer src="siteScript.js" onload="myInit()"></script>

在分析新的adsense广告单元代码时,我注意到了该属性,而搜索将我引到了这里:http : //davidwalsh.name/html5-async


根据我阅读stackoverflow.com/questions/2774373/…的理解,asyn不是用于加载,而是用于确定何时运行所包含的javascript。
JackDev

9
defer属性使浏览器推迟脚本的执行,直到文档被加载和解析并准备好进行操作为止。async属性使浏览器尽快运行脚本,但不会在下载脚本时阻止文档解析
shuseel 2014年

1
“ asyn不是用于加载,而是用于确定何时运行所包含的javascript”。在所有情况下,浏览器都将尽快开始加载脚本。但是如果没有 asyncdefer加载时它将阻止渲染。设置async将告诉它不要阻止并尽快运行脚本。设置defer将告诉它不要阻止,而是等待运行脚本,直到页面完成。通常,只要脚本没有任何依赖性(例如jQuery),就可以尽快运行脚本。如果一个脚本依赖于另一个脚本,请使用onLoad它来等待它。
Stijn de Witt

@StijndeWitt如果既未指定异步也未指定延迟怎么办?
Mohammed Shareef C

@MohammedShareefC如果不指定,则得到的内容与同步行为非常相似;浏览器在下载并运行脚本时会阻止进一步的处理。因此,默认行为实际上是同步。但是由于这会对性能造成不利影响,因此浏览器将尽其所能。他们可以继续解析,加载和应用CSS等。但是,他们无法开始运行下一个脚本片段。所以东西会阻塞。通过设置异步,您可以告诉浏览器可以继续进行,并且可以确保自己运行。
Stijn de Witt

8

当所有脚本完成加载后,我将页面异步重定向到了html 5(html 5具有该功能),我将页面重定向到index2.html,其中index2.html使用相同的库。由于浏览器一旦页面重定向到index2.html便具有缓存,因此index2.html的加载时间不到一秒钟,因为它具有加载页面所需的一切。在index.html页面中,我还加载了计划使用的图像,以便浏览器将这些图像放置在缓存中。所以我的index.html看起来像:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Project Management</title>

    <!-- the purpose of this page is to load all the scripts on the browsers cache so that pages can load fast from now on -->

    <script type="text/javascript">

        function stylesheet(url) {
            var s = document.createElement('link');
            s.type = 'text/css';
            s.async = true;
            s.src = url;
            var x = document.getElementsByTagName('head')[0];
            x.appendChild(s);
        }

        function script(url) {
            var s = document.createElement('script');
            s.type = 'text/javascript';
            s.async = true;
            s.src = url;
            var x = document.getElementsByTagName('head')[0];
            x.appendChild(s);
        }

        //load scritps to the catche of browser
        (function () {            
                stylesheet('css/custom-theme/jquery-ui-1.8.16.custom.css');
                stylesheet('css/main.css');
                stylesheet('css/marquee.css');
                stylesheet('css/mainTable.css');

                script('js/jquery-ui-1.8.16.custom.min.js');
                script('js/jquery-1.6.2.min.js');
                script('js/myFunctions.js');
                script('js/farinspace/jquery.imgpreload.min.js');
                script('js/marquee.js');            
        })();

    </script>

    <script type="text/javascript">
       // once the page is loaded go to index2.html
        window.onload = function () {
            document.location = "index2.html";
        }
    </script>

</head>
<body>

<div id="cover" style="position:fixed; left:0px; top:0px; width:100%; height:100%; background-color:Black; z-index:100;">Loading</div>

<img src="images/home/background.png" />
<img src="images/home/3.png"/>
<img src="images/home/6.jpg"/>
<img src="images/home/4.png"/>
<img src="images/home/5.png"/>
<img src="images/home/8.jpg"/>
<img src="images/home/9.jpg"/>
<img src="images/logo.png"/>
<img src="images/logo.png"/>
<img src="images/theme/contentBorder.png"/>

</body>
</html>

另一个有趣的事情是,我可以在页面中放置一个加载器,当页面加载完成时,加载器将消失,并且在几毫秒内新页面就会运行。


1
@MohammedShareefC具有讽刺意味的是。一个仅用于预加载内容的特殊页面听起来似乎不是SEO明智的主意。预加载很棒,但是您无需重定向即可实现预加载。只需将链接放在隐藏的div中,浏览器就会自动为您处理。然后,不要重定向,而只渲染实际页面。COPY-PASTERS读此:请在使用任何HTML之前将ISO-88591编码更改为UTF-8,以便我们其他人可以在任何时候离开编码地狱。谢谢!
Stijn de Witt


8

谷歌的例子

<script type="text/javascript">
  (function() {
    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })();
</script>

8

几点注意事项:

  • s.async = true对于HTML5 doctype不是非常正确,正确是s.async = 'async'(实际上使用的true 是正确的,这要感谢amn在下面的注释中指出)
  • 使用超时来控制顺序不是很好并且不安全,并且您还使加载时间变得更长,等于所有超时的总和!

由于最近有一个异步加载文件的原因,但是为了顺序,我建议在您的示例中console.log采用更多功能驱动的方式(删除供生产使用:)):

(function() {
    var prot = ("https:"===document.location.protocol?"https://":"http://");

    var scripts = [
        "path/to/first.js",
        "path/to/second.js",
        "path/to/third.js"
    ];

    function completed() { console.log('completed'); }  // FIXME: remove logs

    function checkStateAndCall(path, callback) {
        var _success = false;
        return function() {
            if (!_success && (!this.readyState || (this.readyState == 'complete'))) {
                _success = true;
                console.log(path, 'is ready'); // FIXME: remove logs
                callback();
            }
        };
    }

    function asyncLoadScripts(files) {
        function loadNext() { // chain element
            if (!files.length) completed();
            var path = files.shift();
            var scriptElm = document.createElement('script');
            scriptElm.type = 'text/javascript';
            scriptElm.async = true;
            scriptElm.src = prot+path;
            scriptElm.onload = scriptElm.onreadystatechange = \
                checkStateAndCall(path, loadNext); // load next file in chain when
                                                   // this one will be ready 
            var headElm = document.head || document.getElementsByTagName('head')[0];
            headElm.appendChild(scriptElm);
        }
        loadNext(); // start a chain
    }

    asyncLoadScripts(scripts);
})();

4
s.async = true正确的。该属性asyncw3.org/TR/html5/scripting-1.html#attr-script-async的 W3C HTML 5建议中明确指定为布尔值。您async 会将属性async实现HTMLScriptElementDOM接口的对象公开的属性混淆。确实,当通过诸如来操纵元素的相应属性时Element.setAttribute,您应该使用,element.setAttribute("async", "async")因为所有HTML属性都是头文字。
amn 2016年

“由于最近有一种异步加载文件的原因,但是为了顺序,我建议在您的示例中采用更多功能驱动的方法。我知道异步通常是“更好”的,但是您指的是什么“最近”的原因呢?
BluE

我更改了'if(!files.length)completed();' 添加一个“返回”:'if(!files.length){completed(); 返回;}”
费尔

4

多亏了HTML5,您现在可以通过在标记中添加“ async”来声明要异步加载的脚本:

<script async>...</script>

注意:async属性仅适用于外部脚本(仅当存在src属性时才应使用)。

注意:有几种执行外部脚本的方法:

  • 如果存在异步:脚本与页面的其余部分异步执行(脚本将在页面继续解析的同时执行)
  • 如果不存在异步并且存在延迟:在页面完成解析后执行脚本
  • 如果不存在异步或延迟:在浏览器继续解析页面之前,立即获取并执行脚本

看到这个:http : //www.w3schools.com/tags/att_script_async.asp


2

我将通过检查回调的存在来完成zzzzBov的答案,并允许传递参数:

    function loadScript(src, callback, args) {
      var s, r, t;
      r = false;
      s = document.createElement('script');
      s.type = 'text/javascript';
      s.src = src;
      if (typeof(callback) === 'function') {
        s.onload = s.onreadystatechange = function() {
          if (!r && (!this.readyState || this.readyState === 'complete')) {
            r = true;
            callback.apply(args);
          }
        };
      };
      t = document.getElementsByTagName('script')[0];
      t.parent.insertBefore(s, t);
    }

2

这是异步脚本加载的一种出色的当代解决方案,尽管它仅使用async false解决js脚本。

www.html5rocks.com上有一篇很棒的文章 - 深入了解脚本加载的阴暗水域

在考虑了许多可能的解决方案之后,作者得出结论,将js脚本添加到body元素的末尾是避免由js脚本阻止页面呈现的最佳方法。

同时,作者为那些急于异步加载和执行脚本的人们添加了另一个很好的替代解决方案。

考虑到您已经命名了四个脚本,script1.js, script2.js, script3.js, script4.js那么可以通过应用async = false来做到这一点:

[
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

现在,Spec说:一起下载,全部下载后立即执行。

Firefox <3.6,Opera说:我不知道这个“异步”是什么,但是恰好发生在我按照添加顺序执行通过JS添加的脚本的过程中。

Safari 5.0说:我了解“异步”,但不了解使用JS将其设置为“假”。脚本登陆后,我将以任何顺序执行它们。

IE <10说:没有关于“异步”的想法,但是有一种使用“ onreadystatechange”的解决方法。

其他一切都说:我是你的朋友,我们将按照本书的规定进行操作。

现在,使用IE <10解决方法的完整代码:

var scripts = [
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && ( pendingScripts[0].readyState == 'loaded' || pendingScripts[0].readyState == 'complete' ) ) {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we’ll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

1

脚本加载速度如此之慢的原因之一是,如果在加载页面时正在运行所有脚本,如下所示:

callMyFunctions();

代替:

$(window).load(function() {
      callMyFunctions();
});

脚本的第二部分要等到浏览器完全加载了所有Javascript代码之后,才开始执行您的任何脚本,从而向用户显示页面加载速度更快。

如果您希望通过减少加载时间来提高用户体验,那么我不会选择“加载屏幕”选项。在我看来,这比让页面加载速度更慢要麻烦得多。


1

我建议您看一下Modernizr。它是一个轻巧的小型库,您可以通过功能异步加载JavaScript,该功能使您可以检查文件是否已加载,并在指定的其他脚本中执行脚本。

这是加载jquery的示例:

Modernizr.load([
  {
    load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
    complete: function () {
      if ( !window.jQuery ) {
            Modernizr.load('js/libs/jquery-1.6.1.min.js');
      }
    }
  },
  {
    // This will wait for the fallback to load and
    // execute if it needs to.
    load: 'needs-jQuery.js'
  }
]);

1

我写了一篇文章来帮助解决这个问题,您可以在这里阅读更多内容https://timber.io/snippets/asynchronously-load-a-script-in-the-browser-with-javascript/,但是我已经附上了下面的帮助程序类。它将自动等待脚本加载并返回指定的window属性。

export default class ScriptLoader {
  constructor (options) {
    const { src, global, protocol = document.location.protocol } = options
    this.src = src
    this.global = global
    this.protocol = protocol
    this.isLoaded = false
  }

  loadScript () {
    return new Promise((resolve, reject) => {
      // Create script element and set attributes
      const script = document.createElement('script')
      script.type = 'text/javascript'
      script.async = true
      script.src = `${this.protocol}//${this.src}`

      // Append the script to the DOM
      const el = document.getElementsByTagName('script')[0]
      el.parentNode.insertBefore(script, el)

      // Resolve the promise once the script is loaded
      script.addEventListener('load', () => {
        this.isLoaded = true
        resolve(script)
      })

      // Catch any errors while loading the script
      script.addEventListener('error', () => {
        reject(new Error(`${this.src} failed to load.`))
      })
    })
  }

  load () {
    return new Promise(async (resolve, reject) => {
      if (!this.isLoaded) {
        try {
          await this.loadScript()
          resolve(window[this.global])
        } catch (e) {
          reject(e)
        }
      } else {
        resolve(window[this.global])
      }
    })
  }
}

用法是这样的:

const loader = new Loader({
    src: 'cdn.segment.com/analytics.js',
    global: 'Segment',
})

// scriptToLoad will now be a reference to `window.Segment`
const scriptToLoad = await loader.load()


0

好吧,x.parentNode返回HEAD元素,因此您要在head标签之前插入脚本。也许这就是问题所在。

试试吧x.parentNode.appendChild()




0

您是否考虑过使用提取注入?我推出了一个名为fetch-inject的开源库来处理此类情况。这是使用lib时加载程序的外观:

fetcInject([
  'js/jquery-1.6.2.min.js',
  'js/marquee.js',
  'css/marquee.css',
  'css/custom-theme/jquery-ui-1.8.16.custom.css',
  'css/main.css'
]).then(() => {
  'js/jquery-ui-1.8.16.custom.min.js',
  'js/farinspace/jquery.imgpreload.min.js'
})

为了向后兼容,可以利用功能检测和回退到XHR注入或脚本DOM元素的功能,或者使用来简单地将标记内联到页面中document.write


0

这是我用于消除渲染阻止JavaScript的自定义解决方案:

// put all your JS files here, in correct order
const libs = {
  "jquery": "https://code.jquery.com/jquery-2.1.4.min.js",
  "bxSlider": "https://cdnjs.cloudflare.com/ajax/libs/bxslider/4.2.5/jquery.bxslider.min.js",
  "angular": "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js",
  "ngAnimate": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-animate.min.js"
}
const loadedLibs = {}
let counter = 0

const loadAsync = function(lib) {
  var http = new XMLHttpRequest()
  http.open("GET", libs[lib], true)
  http.onload = () => {
    loadedLibs[lib] = http.responseText
    if (++counter == Object.keys(libs).length) startScripts()
  }
  http.send()
}

const startScripts = function() {
  for (var lib in libs) eval(loadedLibs[lib])
  console.log("allLoaded")
}

for (var lib in libs) loadAsync(lib)

简而言之,它异步加载所有脚本,然后执行它们。

Github仓库https//github.com/mudroljub/js-async-loader


1
不起作用No 'Access-Control-Allow-Origin' header is present on the requested resource
Abram


0

如果有人想在React中使用ES6的一些功能,例如

import {uniqueId} from 'lodash' // optional
/**
 * @param {String} file The path of the file you want to load.
 * @param {Function} callback (optional) The function to call when the script loads.
 * @param {String} id (optional) The unique id of the file you want to load.
 */
export const loadAsyncScript = (file, callback, id) => {
  const d = document
  if (!id) { id = uniqueId('async_script') } // optional
  if (!d.getElementById(id)) {
    const tag = 'script'
    let newScript = d.createElement(tag)
    let firstScript = d.getElementsByTagName(tag)[0]
    newScript.id = id
    newScript.async = true
    newScript.src = file
    if (callback) {
      // IE support
      newScript.onreadystatechange = () => {
        if (newScript.readyState === 'loaded' || newScript.readyState === 'complete') {
          newScript.onreadystatechange = null
          callback(file)
        }
      }
      // Other (non-IE) browsers support
      newScript.onload = () => {
        callback(file)
      }
    }
    firstScript.parentNode.insertBefore(newScript, firstScript)
  } else {
    console.error(`The script with id ${id} is already loaded`)
  }
}


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.