各个浏览器对于ES6模块 import 、 export的支持情况
- Safari 10.1.
- Chrome 61.
- Firefox 54 – behind the dom.moduleScripts.enabled setting in about:config.
- Edge 16.
ES6 import 和 export 在浏览器当中的使用
显示声明type=”module”
script 里面要加 type="module", 这样浏览器才会把相关的代码当作ES6的module 来对待
<script type="module">
import {addTextToBody} from './utils.js';
addTextToBody('Modules are pretty cool.');
</script>
不能写“裸”路径
<script type="module">
import {addTextToBody} from 'utils.js'; // error
addTextToBody('Modules are pretty cool.');
</script>
直接写 'utils.js'
会报错
你可以写绝对路径和相对路径, 但是不能直接写文件名,即使是同一层级下面的文件。也要加上 './name.js'
文件名后缀 .js 必须要有,不然浏览器无法识别路径。
demo
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=11,IE=10,IE=9,IE=8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-mobile-web-app-title" content="">
<link rel="stylesheet" id="wpsm_tabs_r_bootstrap-front-css" href="" type="text/css" />
<script type="text/javascript" src=" "></script>
<link rel="shortcut icon" href="favicon.ico">
<meta name="keywords" content="">
<meta name="description" content="">
<title></title>
</head>
<body>
<script type="module">
import {firstName, lastName, year} from './profile.js';
console.log(firstName);
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
</script>
</body>
</html>
profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
如何向下兼容
使用 "nomodule"
关键字来实现浏览器的向下兼容
<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>
我是这样理解的,老的浏览器本身不会识别type="module" js
,也就不会去有执行有type="module"
的js代码(但是还是会下载的哈)。
也不识别 nomodule
关键字,所以它会忽略nomodule
,即正常执行这个有nomodule
标识的js。
而支持type=“module”的浏览器,它会自动不去执行有nomodule关键字的js。甚至连下都不去下载。
所以向下兼容的功能就走通了(这个大家用不同的浏览器试试,立刻可以明白)
唯一的问题,还有一类浏览器,它支持 type="module" 的 ES6特性,但是它不支持nomodule关键字。也就是说,即使有nomodule标识,它还是会去下载并且执行这个js。即使它已经执行了 type="module"的 js。
这些浏览器有
- Firefox doesn’t support nomodule (issue). Fixed in Firefox nightly!
- Edge doesn’t support nomodule (issue). Fixed in Edge 16!
- Safari 10.1 doesn’t support nomodule. Fixed in Safari 11!
默认加载方式
type=“module”的加载方式默认使用 defer的加载方式。
关于defer
和 async
defer
和async
都是异步加载代码。但是defer
要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行。 async
一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。 一句话,defer
是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer
脚本,会按照它们在页面出现的顺序加载,而多个async
脚本是不能保证加载顺序的。<!-- This script will execute after… -->
<script type="module" src="1.js"></script>
<!-- …this script… -->
<script src="2.js"></script>
<!-- …but before this script. -->
<script defer src="3.js"></script>
内联的 <script>
也是采用的 defer
加载模式
<!-- This script will execute after… -->
<script type="module">
addTextToBody("Inline module executed");
</script>
<!-- …this script… -->
<script src="1.js"></script>
<!-- …and this script… -->
<script> //这里默认采用defer,避免歧义,建议手动加上
addTextToBody("Inline script executed");
</script>
<!-- …but before this script. -->
<script defer src="2.js"></script>
而如果是传统的script 内联js,调用的那个js文件在后面的话,会报错。
支持async的加载方式
type='module'
也可以使用 async
的方式进行加载(包括其内联的 import
),等同普通 js
采用 async
进行加载的方式
<script type="module" async></script>
Browser issues
Firefox doesn’t support async on inline module scripts (issue)
只执行一次
<script type='module'>
只执行一次同ES6的加载机制,多次import
只会被当成一次import
处理
<!-- 1.js 只会被加载执行一次-->
<script type="module" src="1.js"></script>
<script type="module" src="1.js"></script>
<script type="module">
import "./1.js";
</script>
<!-- 普通JS 也只会被加载一次,但是会被执行多次-->
<script src="2.js"></script>
<script src="2.js"></script>
Browser issues
Edge executes modules multiple times (issue). Fixed, but not yet shipped (expect Edge 17 to ship with the fix).
关于CORS
type=”module”
默认不支持跨域,这一点儿与传统js或图片完全不一样。传统js或图片默认就是支持跨域的。
如果你想 type=”module”
支持跨域。需要在从服务器返回的header
上显示的给予有效的CORS
声明
Access-Control-Allow-Origin: *
Browser issues
Firefox fails to load the demo page (issue).
Edge loads module scripts without CORS headers (issue). Fixed in Edge 16!