咱们聊一聊如何让现代浏览器更高效的加载JavaScript代码。

让现代浏览器加载现代标准的JavaScript代码(ES6+)会更高效,但是通常来讲我们都会把代码转换成旧版本(ES5版本)的Javascript代码,以便支持老式浏览器。

所以,即想让拥有新浏览器的用户体验到极致的性能,又想让一些过时的浏览器能够正常加载代码,我们可以将打包工具配置为生成两份JavaScript代码,一份是现代的(ES6+)JavaScript代码,另一份是适合旧版浏览器的常规代码。


除了es 还是什么文本搜索 除了es文件浏览器_HTML

这两份文件都以script标签的方式引入到html,浏览器会基于script的type和nomodule属性去选择去用哪一个文件。

怎么办?

怎么办?我们想在浏览器中按需选择加载哪一份JavaScript代码,但总有一些浏览器不太听话。

首先,在 Safari 10.1 里,就存在这个问题,Safari 10.1 支持 ES Module,但是不支持script标签的nomodule属性,所以这个浏览器会把ES6+的代码和老式代码都执行一次。幸运的是,已经有人完美的解决了这个问题,通过使用Safari浏览器中非标准的beforeload事件让Safari10.1支持了这个属性。具体代码在下文中列出。

其次,我们还有别的方法。

  1

第一种方案

通过一小段JS代码能规避这个这个问题。

我们不依赖浏览器内建的选择机制去加载JavaScript代码,我们尝试先运行一段 type="module" 的JavaScript代码来看看浏览器支持不支持module写法,然后根据不同的支持程度去加载不同的代码。


除了es 还是什么文本搜索 除了es文件浏览器_html浏览文件_02

但是,这个方法有一些缺陷。我们在注入JS代码之前需要等待onload事件。这是因为 type="module" 的script标签总是以defer的方式执行的。另一个方法是,检测浏览器是否支持nomodule属性。这意味着像Safari 10.1这样实际上支持JS Module的浏览器会去加载老式的JavaScript代码。但这实际上也不是什么问题。


除了es 还是什么文本搜索 除了es文件浏览器_除了es 还是什么文本搜索_03

我们进一步包装成一个方法:


除了es 还是什么文本搜索 除了es文件浏览器_ES6_04

这样做也会有些问题,使得浏览器没办法预加载JS脚本了。

因为这个方法是完全的动态加载,浏览器当没运行到这段代码的时候根本不知道需要加载什么代码。通常情况下,浏览器会一边下载HTML一边去查看HTML里哪些资源能够预加载。当然了,这也有解决办法,虽说不太完美:通过使用带有 rel="modulepreload" 的link标签,告诉浏览器预先加载JS文件。但是还有个问题,目前只有Chrome支持。


除了es 还是什么文本搜索 除了es文件浏览器_除了es 还是什么文本搜索_05

这个方法效果好不好取决于HTML文档的体积大小。如果你的HTML文件只是个启动页,或者是个只有寥寥几个的标签,那么这种方法不太会影响到性能。如果你采用了诸如 server render 这样的方式,HTML文档是一个有内容的很大的文件,那么这种方法就不是太适合了,因为在这种情况下预先加载JS还是很重要的。在生产环境下,我们可以这么写:


除了es 还是什么文本搜索 除了es文件浏览器_HTML_06

根据统计,大部分支持  的浏览器也支持 JS Module。所以,我们也可以使用  来替代 modulepreload。这可能在性能上稍有一些让步,因为普通的  不会提前解析JS,而 modulepreload 却可以。

2

第二种方案

还可以通过服务端去判断到底要加载哪个JS文件。

让所有浏览器都通过