除了静态的<script>标签,还可以动态生成<script>标签,然后加入页面,从而实现脚本的动态加载。例如:
['a.js', 'b.js'].forEach(function(src) { var script = document.createElement('script'); script.src = src; document.head.appendChild(script); });
这种方法的好处是,动态生成的<script>标签不会阻塞页面渲染,也就不会造成浏览器假死。但是问题在于,这种方法无法保证脚本的执行顺序,哪个脚本文件先下载完成,就先执行哪个。
如果想避免这个问题,可以设置async属性为false。例如:
['a.js', 'b.js'].forEach(function(src) { var script = document.createElement('script'); script.src = src; script.async = false; document.head.appendChild(script); });
上面的代码依然不会阻塞页面渲染,而且可以保证b.js在a.js后面执行。不过需要注意的是,在这段代码后面加载的脚本文件,会因此都等待b.js执行完成后再执行。
把上面的写法封装成一个函数。
(function () { var scripts = document.getElementsByTagName('script')[0]; function load(url) { var script = document.createElement('script'); script.async = true; script.src = url; scripts.parentNode.insertBefore(script, scripts); } load('//apis.google.com/js/plusone.js'); load('//platform.twitter.com/widgets.js'); load('//s.thirdpartywidget.com/widget.js'); }());
在上面代码中,async属性设为true,是因为加载的脚本没有互相依赖关系。而且,这样就不会造成堵塞。
如果想为动态加载的脚本指定回调函数,可以使用下面的写法。例如:
function loadScript(src, done) { var js = document.createElement('script'); js.src = src; js.onload = function () { done(); }; js.onerror = function () { done(new Error('加载失败:' + src)); }; document.head.appendChild(js); }
此外,动态嵌入还有一个地方需要注意。动态嵌入必须等待CSS文件加载完成后,才会去下载外部脚本文件。静态加载就不存在这个问题,<script>标签指定的外部脚本文件,都是与CSS文件同时并发下载的。