[译] 浏览器中的 ECMAScript 模块

news/2025/5/29 3:35:13
原文链接:ECMAScript modules in browsers

作者:Jake Archibald

浏览器现在可以使用 ES 模块(module)了!它们是:

  • Safari 10.1
  • Chrome 61
  • Firefox 60
  • Microsoft Edge 16
<script type="module">import {addTextToBody} from './utils.mjs';addTextToBody('Modules are pretty cool.');
</script>
// utils.mjs
export function addTextToBody(text) {const div = document.createElement('div');div.textContent = text;document.body.appendChild(div);
}

在线演示

您只需要在 script 元素上添加 type=module,浏览器就会将内联脚本或外部脚本作为 ECMAScript module 处理。

关于模块(module)已经有一些很棒的文章,但是我想分享一些在我测试和阅读规范的时候学到的浏览器特有的内容。

目前还不支持的某些 import 用法

// 已支持:
import {foo} from 'https://jakearchibald.com/utils/bar.mjs';
import {foo} from '/utils/bar.mjs';
import {foo} from './bar.mjs';
import {foo} from '../bar.mjs';// 不支持:
import {foo} from 'bar.mjs';
import {foo} from 'utils/bar.mjs';

有效的模块路径说明符必须符合下列条件之一:

  • 一个完整的非相对URL,这样在将其传给 new URL(moduleSpecifier) 的时候才不会报错。
  • / 开头的。
  • ./ 开头的。
  • ../ 开头的。

其他形式的说明符保留供将来使用,例如导入内置模块。

使用 nomodule 来向后兼容

<script type="module" src="module.mjs"></script>
<script nomodule src="fallback.js"></script>

在线演示

支持 type=module 的浏览器会忽略属性为 nomodule 的脚本。这意味着您可以给支持模块的浏览器提供模块树,同时给其他浏览器提供一个降级版本。

浏览器问题

  • Firefox 浏览器不支持 nomodule (issue)。已在 Firefox nightly 中修复!
  • Edge 浏览器不支持 nomodule (issue)。已在 Edge 16 中修复!
  • Safari 浏览器不支持 nomodule。已在 Safari 11 中修复!对于 10.1,这里有一个非常聪明的替代办法。

默认情况下延迟执行

<!-- 这个脚本的执行会晚于… -->
<script type="module" src="1.mjs"></script><!-- …这个脚本… -->
<script src="2.js"></script><!-- …但是会在这个脚本之前执行。 -->
<script defer src="3.js"></script>

在线演示

执行的顺序是:2.js1.mjs3.js

script 在获取期间会阻塞 HTML 解析器,简直太糟糕了。对于常规脚本,您可以使用 defer 来避免阻塞,当然这也会推迟脚本的执行,直到文档完成解析,并与其他延迟脚本一起维护执行顺序。模块脚本的默认表现行为就像 defer ——当它正在获取时,没有办法让一个模块脚本阻塞 HTML 解析器。

模块脚本使用和添加了 defer 的常规脚本相同的执行队列。

内联脚本也是延时的

<!-- 这个脚本的执行会晚于… -->
<script type="module">addTextToBody("Inline module executed");
</script><!-- …这个脚本… -->
<script src="1.js"></script><!-- …和这个脚本… -->
<script defer>addTextToBody("Inline script executed");
</script><!-- …但是会在这个脚本之前执行。 -->
<script defer src="2.js"></script>

在线演示

执行顺序是1.js ,内联脚本,内联脚本,2.js

常规的内联脚本会忽略 defer ,然而内联模块脚本却总是被延迟,无论它们有没有导入任何东西。

Async 对内联、外部模块同样适用

<!-- 一旦获取了导入,就会执行此操作 -->
<script async type="module">import {addTextToBody} from './utils.mjs';addTextToBody('Inline module executed.');
</script>
<!-- 一旦获取了脚本和它的导入,就会执行此操作 -->
<script async type="module" src="1.mjs"></script>

在线演示

快速下载的脚本会在慢速下载的脚本之前执行。

与常规脚本一样,async 会让脚本在下载过程中不会阻塞 HTML 解析器,并且尽快地执行。与常规脚本不同,async 也适用于内联模块。

与往常的 async 一样,脚本不会按照它们出现在 DOM 中的顺序执行。

浏览器问题

  • Firefox 浏览器不支持内联模块脚本上的 async (issue)。已在 Firefox 59 中修复!

模块仅执行一次

<!-- 1.mjs 仅执行一次 -->
<script type="module" src="1.mjs"></script>
<script type="module" src="1.mjs"></script>
<script type="module">import "./1.mjs";
</script><!-- 然而,普通的脚本却执行多次 -->
<script src="2.js"></script>
<script src="2.js"></script>

在线演示

如果您理解 ES 模块,您就会知道您虽然可以引入它们很多次,但是它们却仅仅会执行一次。当然,这同样适用于HTML中的脚本模块 - 特定URL的模块脚本每页只执行一次。

浏览器问题

  • Edge 执行多次模块 (issue)。已修复,但是还没发布(希望 Edge 17 会带上这个修复内容)。

总是使用 CORS

<!-- 该脚本不会执行, 因为它不能通过 CORS 检查 -->
<script type="module" src="https://….now.sh/no-cors"></script><!-- 该脚本不会执行, 因为它引入的脚本之一不能通过 CORS 检查 -->
<script type="module">import 'https://….now.sh/no-cors';addTextToBody("This will not execute.");
</script><!-- 该脚本会执行,因为它通过了 CORS 检查 -->
<script type="module" src="https://….now.sh/cors"></script>

在线演示

与常规脚本不同,模块脚本(及其引入的内容)是通过 CORS 获取的。这就意味着跨域的模块脚本必须返回有效的 CORS 响应头 ,比如 Access-Control-Allow-Origin: *

浏览器问题

  • Firefox 加载 Demo 页面失败 (issue)
  • Edge 加载没有 CORS header 的模块脚本 (issue)。 已在 Edge 16 中修复!

不携带凭据

<!-- 携带凭据获取(cookie 等) -->
<script src="1.js"></script><!-- 不携带凭据获取 -->
<script type="module" src="1.mjs"></script><!-- 携带凭据获取 -->
<script type="module" crossorigin src="1.mjs?"></script><!-- 不携带凭据获取 -->
<script type="module" crossorigin src="https://other-origin/1.mjs"></script><!-- 携带凭据获取 -->
<script type="module" crossorigin="use-credentials" src="https://other-origin/1.mjs?"></script>

在线演示

如果请求来自相同的源,大多数基于 CORS 的 API 会发送凭据(cookie 等),但是 fetch() 和模块脚本却是例外的——非您要求它们,否则它们不会发送凭据除。

您可以通过添加 crossorigin 属性来向同源模块添加凭据(这对我来说似乎有点奇怪,我在规范中对此提出质疑)。如果您打算向其他的源也发送凭据,使用 crossorigin="use-credentials"。注意其他源必须使用 Access-Control-Allow-Credentials:true 的响应头来响应。

此外,还有一个与“模块只执行一次”规则相关的问题。模块由其URL标记,因此如果首次请求了一个模块而不携带凭据,然后再次携带凭据请求该模块,那么第二次获得的依然是不携带凭证的模块。 这就是为啥我在上面的URL中使用 问号 ? 的原因,使它们成为唯一的。

更新: 上面的情况可能很快就会发生改变。fetch() 和模块脚本默认都会向同源的 URL 发送凭据。Issue

浏览器问题

  • Chrome 使用凭据请求同源模块(issue)。已在 Chrome 61 中修复!
  • Safari 即使添加了 crossorigin 属性,也不使用凭据请求同源模块(issue)。
  • Edge 即使添加了 crossorigin 属性,也不使用凭据请求同源模块(issue)。已在 Edge 16 中修复!
  • Edge 默认请求同源模块的时候携带了凭据(issue)。

MIME 类型

不同于常规脚本,模块脚本必须是有效的 JavaScript MIME 类型中的一种类型,否则模块就不会执行。HTML 标准建议使用 text/javascript

浏览器问题

  • Edge 执行无效的 MIME 类型脚本(issue)

这就是我目前学到的内容啦。毋庸置疑,我对 ES 模块登陆浏览器感到非常兴奋!

性能建议,动态导入等等!

请查阅有关 Web Fundamentals 的文章,深入了解模块使用情况。

文章来源:https://blog.csdn.net/weixin_33712881/article/details/88659002
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:https://dhexx.cn/news/show-1817587.html

相关文章

Scrum立会报告+燃尽图(十月二十一日总第十二次)

此作业要求参见&#xff1a;https://edu.cnblogs.com/campus/nenu/2018fall/homework/2246 项目地址&#xff1a;https://git.coding.net/zhangjy982/QuJianBang.git Scrum立会master&#xff1a;于洋 一、小组介绍 组长&#xff1a;付佳 组员&#xff1a;张俊余 李文涛 孙赛佳…

教你用认知和人性来做最棒的程序员

不久前&#xff0c;在团队内部和大家做了一次分享&#xff0c;内容就是这次要讲的“用认知和人性来提升自己的技术水平”&#xff0c;大家反响不错&#xff0c;所以这次整理一下也分享给大家。最初我是想用“借优秀的产品经理思维来做最棒程序员”的这个标题&#xff0c;但想想…

Kotlin系列之变量和函数

这一节我们将学习Kotlin的变量和函数。 Kotlin的变量 1 . Kotlin的变量声明格式 Kotlin中的变量声明以关键字开始&#xff0c;在大部分情况下可以省略类型&#xff0c;这里我们同样将Kotlin与Java进行对比 Kotlin变量声明格式如下&#xff1a; //关键字 变量名:类型(可省略) v…

java ffmpeg视频转码(自测通过)

import java.io.*;public class VideoTransfer {//ffmepg文件 安装目录private static String ffmpeg "D:\\开发常用工具\\ffmpeg-20181018-f72b990-win64-static\\bin\\ffmpeg";public static void main(String args[]) {String infile "d://2//64891541678_…

自然语言处理NLP学习笔记

1.自然语言处理是什么&#xff1f; NLP&#xff08;Natural Language Processing&#xff09; NLU&#xff08;Understand&#xff09;NLG&#xff08;Generation&#xff09; 自然语言处理 自然语言理解自然语言生成 NLU 负责理解内容&#xff0c;NLG 负责生成内容。 例如商场…

HDU 1068 Girls and Boys(最大独立集)

/* 题意&#xff1a;n个同学&#xff0c;一些男女同学会有缘分成为情侣&#xff0c;格式ni:(m) n1 n2 n3表示同学ni有缘与n1,n2,n3成为情侣&#xff0c;求集合中不存在有缘成为情侣的同学的最大同学数。 题解&#xff1a; 独立集&#xff1a;图的顶点集的子集&#xff0c;其中任…

Windows Mobile下如何去掉WTL对话框CStdDialogImpl的OK按钮

简介 本文讲述如何去掉WTL对话框的右上角的OK按钮。 问题 继承于CStdDialogImpl类的对话框默认是有一个OK按钮在右上角的。如下图 为什么会有这个OK按钮呢&#xff0c;因为模拟生产的代码是继承于CStdDialogImpl<CConfigDialog>,CConfigDialog为自定义的类。 class CConf…

Greenplum小把戏 - 快速复制无数据SCHEMA

为什么80%的码农都做不了架构师&#xff1f;>>> 今天分享一条简单的命令&#xff0c;帮助大家尽快的复制一个新的SCHEMA。话不多说&#xff0c;看例子&#xff1a; 首先创建一个有三个表&#xff08;t1\t2\t3&#xff09;的新模式(test1): postgres# \dList of rel…

Java基础(一)——Java概述、dos命令、JDK、JRE、JVM、跨平台性、编译解释等

目录 第一章 Java基础语法 1.1Java语言概述 1.2常用dos命令 1.3java环境配置简述 1.4 JDK 与JRE 1.5 跨平台特性&#xff08;在任意os下都可以运行&#xff09; 第二章&#xff1a;案例介绍 2.1 java程序介绍 2.1.1 用记事本编写java源文件 第三章 注释、关键字与标识…

小程序里的alert的表示方法wx.showToas

WCML<view bindtap"viewTap">绑定了事件</view>JSviewTap:function(){ wx.showToast({ title: 成功, icon: success, duration: 2000 }) } 学习链接&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showToast.html…