如何动态加载和使用/调用javascript

How load and use/call dynamically JavaScript

我需要动态加载一个javascript文件,然后访问它的内容。

文件test.js

1
2
3
4
5
test = function () {
    var pub = {}
    pub.defult_id = 1;
    return pub;
}()

< BR>在这种情况下,它可以工作:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="/test.js">    
</head>
<body>
    <script type="text/javascript">
        console.log(test.defult_id);
   
</body>
</html>

< BR>但是我需要动态地加载它,这样它就不工作了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <script type="text/javascript">
        function loadjs(file) {
            var script = document.createElement("script");
            script.type ="application/javascript";
            script.src = file;
            document.body.appendChild(script);
        }
        loadjs('test.js');
        console.log(test.defult_id);
   
</body>
</html>

< BR>错误:Uncaught ReferenceError: test is not defined(…)


你可以这样做:

1
2
3
4
5
6
7
8
9
10
function loadjs(file) {
    var script = document.createElement("script");
    script.type ="text/javascript";
    script.src = file;
    script.onload = function(){
        alert("Script is ready!");
        console.log(test.defult_id);
    };
    document.body.appendChild(script);
 }

有关更多信息,请阅读本文:https://www.nczonline.net/blog/2009/06/23/loading-javascript-without-blocking/


在www.html5rocks.com上,有一篇很好的文章值得所有对JS脚本加载感兴趣的人阅读——深入到脚本加载的黑暗水域。

在那篇文章中,在考虑了许多可能的解决方案之后,作者得出结论,在body元素的末尾添加JS脚本是避免JS脚本阻塞页面呈现从而加快页面加载时间的最好方法。

但是,作者为那些迫切希望异步加载和执行脚本的人提出了另一个好的替代解决方案。

考虑到您有四个名为script1.js, script2.js, script3.js, script4.js的脚本,那么您可以通过应用async=false来完成它:

1
2
3
4
5
6
7
8
9
10
11
[
  '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);
});

现在,规范说:一起下载,在所有下载之后按顺序执行。

Firefox<3.6,Opera说:我不知道这是什么"异步"的东西,但它只是这样发生,我执行通过JS添加的脚本,按照它们添加的顺序。

Safari5.0说:我理解"异步",但不理解用JS将其设置为"假"。你的剧本一落地,我就按顺序执行。

IE<10表示:不知道"异步",但有一个使用"onreadystatechange"的解决方案。

其他一切都说:我是你的朋友,我们会按计划来做的。

现在,Ie<10变通方案的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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') {
    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>');
  }
}

一些技巧和缩小后,它是362字节

1
2
3
4
!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
 "//other-domain.com/1.js",
 "2.js"
])


通常加载JS文件是异步的,因此为了确保在调用内部某个函数之前加载脚本,请在脚本中使用onload事件:

1
2
3
4
5
6
7
8
9
10
11
function loadjs(file) {
            var script = document.createElement("script");
            script.type ="application/javascript";
            script.onload=function(){
                //at this tine the script is loaded
                console.log("Script loaded!");
                console.log(test);
            }
            script.src = file;
            document.body.appendChild(script);
        }