以下是来自南德意志的实习生 Pascal Klau 的客座文章,他不喜欢不必要的 HTTP 请求和西兰花。Pascal 将解释如何以一种可能根本不需要使用它的方式使用 polyfill 服务。
情况
我们想用 ES6 语法 编写 JavaScript。但由于我们需要支持不理解 ES6 的旧版浏览器,因此需要处理这个问题。
这是标准流程:编写 ES6 → 将所有内容编译为 ES5(例如 Babel)→ 发送到浏览器。
这可能不再是最有效的方法。问题在于,我们强迫现代浏览器运行它们不需要的旧代码。 它们支持 ES6,那么我们能否向它们提供 ES6 呢?
更好的方法
有一个名为 Polyfill.io API 的 polyfill 项目可以在客户端对 ES6 代码进行 polyfill。

它还为一些 HTML 功能(如 <picture>
元素)实现了 polyfill。
来自其网站的描述
Polyfill.io 读取每个请求的 用户代理 (UA) 标头,并返回适合请求浏览器的 polyfill。根据您在应用中使用的功能定制响应 […]
它由 金融时报 开发,因此它具有一定的支持,我们可以相当肯定它不会消失。
有一点需要明确:Polyfill.io 不提供对语法糖的支持。例如,类、增强的对象文字以及箭头函数之类的东西。您仍然需要编译器才能使用它们。
设置 Polyfill.io
将 Polyfill.io 添加到您的项目可以非常简单。将 CDN 托管的脚本添加到您的页面
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
运行脚本会输出 UA 和您想要的功能。
UA detected: chrome/56.0.0
Features requested: default
更改请求参数
有一些 选项 可以自定义您放入脚本源中的请求。
功能
要进行 polyfill 的浏览器功能列表。接受以逗号分隔的功能名称列表。可在 浏览器和功能页面 上查看可用的功能名称。
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch"></script>
在 Safari 10 中,脚本现在显示如下
Features requested: fetch
- setImmediate, License: CC0 (required by "Promise", "fetch")
- fetch
如果像 fetch 这样的功能依赖于像 Promise 这样的其他功能,Polyfill.io 会自动添加它。
标志
- always – 无论发出请求的用户代理是否需要,都应包含 Polyfill。
- gated – 如果 polyfill 包含在捆绑包中,它将附带一个功能检测,只有在不存在原生 API 时才会执行 polyfill。
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch&flags=gated"></script>
回调
加载 polyfill 后要调用的函数的名称。这仅仅是一种在 polyfill 加载后触发您自己代码的方式,旨在允许更轻松地使用 async 和 defer 属性异步加载 polyfill 服务。
问题
尽管这一切听起来都很好,但它仍然不完美。
现代浏览器不必加载 ES5,而是必须进行服务器往返行程(HTTP 请求)以检查是否需要 polyfill。
这让我非常苦恼,因此我开发了一个小项目来提供帮助。
更好的方法
设置动态 polyfill
我创建的 npm 包称为 dynamic-polyfill。它在进行任何服务器请求之前检查功能是否得到原生支持。
设置如下所示
import polyfill from 'dynamic-polyfill'
polyfill({
fills: 'fetch, Promise',
options: 'gated', // default: null
minify: false, // default: true
afterFill() {
main()
}
})
function main() {
// app code here
}
这将使用简单的语言执行如下操作
[window.fetch, window.Promise] 是否存在?
如果存在,则运行 afterFill()
回调。
如果不存在,则创建一个带有 async
属性的 <script>
标签,插入包含所有提供的选项的 Polyfill.io 链接,并在其加载完成后运行 afterFill()
回调。
注意:并非所有选项都得到支持,仅支持最重要的选项。
较小的占用空间
由于此模块缩小后小于 1KB并且没有任何依赖项,因此它在您的项目中占用空间非常小。
结论
为现代浏览器编写面向未来的高效 JavaScript。让 Polyfill.io 处理旧版浏览器。如果不需要,请不要执行额外的 HTTP 请求。
只需确保您有一些东西可以擦干这些喜悦的泪水。
这篇文章似乎有点奇怪。它谈到了使用“ES6 语法”编写,但随后又谈到了“为功能提供 polyfill”。无论多么有针对性,任何数量的 polyfill 都无法在旧版浏览器中获得箭头函数、const、let 或其他语法。
我对这一点也感到非常困惑。那么我们如何处理 ES2015+ 语法呢?我们是否仍然需要编译它,但以某种方式不包含 ES2015+ 库?但如果这样,我们如何让它与模块加载器一起工作呢?:X
真正酷的一件事可能是,能够在支持的浏览器中直接加载 ES2015 代码(包括语法),同时仍然为不支持(或部分支持)的浏览器提供 ES5 代码。不过,我仍然不确定模块加载器将如何工作。而且这会使调试工作加倍,因为根据支持与否,存在两种不同的执行路径。
我认为这里存在一个混淆,即 ES6 语法无法进行 polyfill 并且在旧版浏览器中会抛出错误,而新的 JS API 可以进行 polyfill。
如果你想支持旧版浏览器,就不能跳过 ES6 到 ES5 的转换。
在我看来,这完全没有用。因此,你浪费了一个额外的 HTTP 请求去向第三方 API 请求 Array.values 或 String.contains 的 polyfill,但你仍然必须使用 ES5 编写代码,即不使用箭头函数、默认参数、解构等。并且如果他们的网站宕机或速度缓慢,你就会遇到麻烦。
抱歉,我真的不明白有什么意义。
是的,这听起来只会进一步加剧 ES 版本的碎片化。你将拥有 ES6、转换后的 ES6、ES6(但不包含类、=> 等)、ES5、Modernizr…
为什么我们不只是进行特性检测并动态触发转换后的或 ES6 库的不同加载呢?这可以在根文档中作为一个 polyfill(如果使用 SPA,否则会更复杂),因此我们不需要浪费宝贵的请求。
类似于(非常快速和粗略的)
我仍然认为,在原生支持 ES6 导入之前,在大多数实际情况下下载几 KB 的 Babel polyfill 是完全可以接受的。
在查看库中的代码后,它甚至无法正常工作……存储库中甚至没有任何测试。
这篇文章应该由 Chris 或 CSS-Tricks 团队的其他成员进行审查和代码测试,以确保其正常工作。
如果你遇到任何方面的问题
“它无法工作!”对任何人都没有帮助。:)
在我看来它运行良好。你遇到了什么问题?
谢谢 http://www.altunyusufelihaliyikama.com
你好,Pascal Klau,
感谢分享,文档看起来非常有用且有吸引力,我们也希望在我们的项目中使用它,但我发现参考文件里没有任何内容,所有文件都是空的,https://polyfill.io/v2/polyfill.min.js 或 https://polyfill.io/v2/polyfill.js,这是假的 URL 吗?
当我浏览 https://polyfill.io/v2/polyfill.min.js 时,我得到了以下消息
当我按照提供的说明从 URL 中删除 min 时,我得到了以下消息
您能否提供更多详细信息,以防 URL 最近进行了任何更改?
提前感谢 :)
我认为这就是重点。它已经确定你正在使用 Chrome 55 并且不需要任何 polyfill。(但你仍然需要发出 HTTP 请求才能确定这一点)