在单页应用程序中有多个文件的情况下,Javascript异步延迟执行顺序

在单页应用程序中有多个文件的情况下,Javascript异步延迟执行顺序,javascript,html,performance,asynchronous,deferred,Javascript,Html,Performance,Asynchronous,Deferred,我正在努力提高页面的页面加载性能,这是在EmberJS上实现的 我正在考虑在我们的Javascript文件上使用asyc和defer。所有其他优化都已经完成(将脚本移动到页面底部,将async和defer添加到分析标签等) 现在,根据ember cli规范,生成的index.html有两个脚本标记-一个供应商JS文件和一个应用程序JS文件 如果我要实现异步和延迟,我需要确保在加载我的应用程序JS文件之前加载我的供应商JS文件,以确保后者具有初始化应用程序所需的所有代码 我理解,使用async和d

我正在努力提高页面的页面加载性能,这是在EmberJS上实现的

我正在考虑在我们的Javascript文件上使用
asyc
defer
。所有其他优化都已经完成(将脚本移动到页面底部,将
async
defer
添加到分析标签等)

现在,根据
ember cli
规范,生成的
index.html
有两个脚本标记-一个供应商JS文件和一个应用程序JS文件

如果我要实现
异步
延迟
,我需要确保在加载我的应用程序JS文件之前加载我的供应商JS文件,以确保后者具有初始化应用程序所需的所有代码

我理解,使用
async
defer
定义脚本时,获取和解析脚本的顺序是不同的

我的问题是:


如果在同一个页面中有多个JS文件,有没有办法按规定的顺序获取和执行它们?我在异步请求中寻找回调/承诺之类的东西,但是就实际的
脚本
标记本身而言。我可以想出两种方法

a) 照你说的做。i、 e.有一个脚本标记,其中包含两个链接承诺,每个脚本标记创建一个新的脚本标记,将其附加到DOM,添加一个
onload
事件函数,该函数将是承诺的
resolve
函数,最后将其
src
属性设置为资源的URL。当第一个承诺中的脚本加载时,第二个承诺应该执行并执行相同的操作

b) 走中间道路。将供应商文件放在头部,以便同步加载,并将应用程序文件放在文档的最底部,以便在完成所有其他操作后加载

在我看来,第一种选择是过度杀戮

编辑:示例a)


var p=新承诺(功能(解决、拒绝){
var scriptTag=document.createElement('script');
document.head.appendChild(scriptTag);
scriptTag.onload=解析;
scriptTag.src='URL_到_供应商_文件';
});
p、 然后(函数(){
var scriptTag=document.createElement('script');
document.head.appendChild(scriptTag);
scriptTag.src='URL_到_应用程序_文件';
};

注意:上面的例子可以写出来,不使用承诺,我可以想到两种方法

a) 照你说的做。i、 e.有一个脚本标记,其中包含两个链接承诺,每个脚本标记创建一个新的脚本标记,将其附加到DOM,添加一个
onload
事件函数,该函数将是承诺的
resolve
函数,最后将其
src
属性设置为资源的URL。当第一个承诺中的脚本加载时,第二个承诺应该执行并执行相同的操作

b) 走中间道路。将供应商文件放在头部,以便同步加载,并将应用程序文件放在文档的最底部,以便在完成所有其他操作后加载

在我看来,第一种选择是过度杀戮

编辑:示例a)


var p=新承诺(功能(解决、拒绝){
var scriptTag=document.createElement('script');
document.head.appendChild(scriptTag);
scriptTag.onload=解析;
scriptTag.src='URL_到_供应商_文件';
});
p、 然后(函数(){
var scriptTag=document.createElement('script');
document.head.appendChild(scriptTag);
scriptTag.src='URL_到_应用程序_文件';
};

注意:上面的示例可以编写,并且不使用承诺

自从这个问题第一次发布以来,事情可能已经变得更好了,但似乎在2019年,您可以推迟脚本,并按照脚本标记写入html文档的顺序处理它们您的
vendor
脚本和
main
脚本将使它们并行加载,而不是阻止html文档的解析,并在文档解析完成时按顺序进行处理

whatwg脚本文档的这一部分详细介绍了我将在这里总结的内容:

  • 如果脚本的类型是“classic”(而不是
    type=“module”
    ),并且元素具有
    src
    属性,并且元素具有
    defer
    属性,并且元素被标记为“parser inserted”,并且元素没有
    async
    属性

  • 然后将该元素添加到将要创建的脚本列表的末尾 尽快按与节点关联的顺序执行 准备脚本时脚本元素的文档 算法启动了

查看该链接以了解完整的详细信息,但实际上它似乎在说,延迟脚本将按照它们在html文档中解析的顺序进行处理

同意:

带有
defer
属性的脚本将按以下顺序执行: 它们出现在文档中

另一个需要注意的要点(来自同一MDN文档):

带有
defer
属性的脚本将阻止
DOMContentLoaded
事件触发,直到脚本加载并完成计算

还值得注意的是,whatwg和MDN都没有提到将脚本标记放在html文档的头部或底部。如果所有脚本都具有
defer
属性,则在html文档完成解析后,它们将按发生顺序进行处理。将脚本标记放在头部这意味着他们将在html文档解析过程的早期开始下载,而不是稍后,当他们被放在正文的底部时
<script>
var p = new Promise(function(resolve, reject) {
    var scriptTag = document.createElement('script');
    document.head.appendChild(scriptTag);
    scriptTag.onload = resolve;
    scriptTag.src = 'URL_to_vendor_file';
});

p.then(function() {
  var scriptTag = document.createElement('script');
    document.head.appendChild(scriptTag);
    scriptTag.src = 'URL_to_application_file';
};
</script>