网站首页 > 开源技术 正文
大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
前不久关于core-js作者的事情在科技圈闹得沸沸扬扬,具体可以阅读我的文章《前端地震!core-js作者放弃开源?》,今天将带着大家一起细数前端周均下载百万、甚至千万级别的Polyfill。话不多说,直接开始!
什么是polyfill?
polyfill 是通过修补 API 来添加缺失功能的代码,典型的例子是通过polyfill在旧浏览器中添加新功能。 例如,Modernizr 检测浏览器功能并使用一组 polyfill 来启用旧浏览器中的浏览器功能,或者提供尚不支持的功能的补丁。
下面代码是笔者用于处理Android 4.4以下浏览器webview不支持部分功能的代码,分别添加了url-polyfill(可以使用new URL)、babel-polyfill、es5-shim(部分代码兼容)这3个polyfill:
<!--url-polyfill.min.js-->
<script src="/1.js"></script>
<!--babel-polyfill/6.26.0/polyfill.min.js-->
<script src="/2.js"></script>
<!--es5-shim/4.6.7/es5-shim.min.js-->
<script src="/3.js"></script>
这种解决方案的问题是:因为它们是修补缺失的API方法,所以特点是污染全局作用域。至于如何解决,以前写过一篇文章《前端 Polyfill、Ponyfill、Prollyfill 傻傻分不清楚?》单独论述过,本文将重点关注在前端的热门polyfill上。
core-js
Core-js是JavaScript 的模块化标准库。 包括 ECMAScript 的 Polyfill 到 ES2023,主要囊括:Promise、Symbol、Collections、 Iterators、 Typed Arrays,、类型数组以及诸多其他特性、ECMAScript 提案、一些跨平台的 WHATWG/W3C 特性和提案等等。
将上面的简短介绍拆开来看,主要包括以下核心特性:
- Core-js是JavaScript 标准库中最流行和最通用的 polyfill:它为最新的 ECMAScript 标准和提案提供支持,从古老的 ES5 功能到迭代器等前沿功能,以及与 ECMAScript 密切相关的 Web 平台功能,如 structuredClone等等。
- Core-js是最复杂和最全面的 polyfill 项目: core-js 包含大约 5000 个复杂程度不同的 polyfill 模块(NPM文件数量显示为3331),从 Object.hasOwn 或 Array.prototype.at 到 URL、Promise 或 Symbol等等。
- Core-js最大限度地模块化:可以允许开发者仅加载需要的功能,而且可以不污染全局命名空间。
- Core-js不是一个框架,其专为与工具集成而设计,并提供了为此所需的一切。例如:babel-polyfill、@babel/preset-env、@babel/transform-runtime,类似的 SWC 功能都基于 core-js,而且最重要的是开发无感,开箱即用。
比如通过如下方式引入core-js将不会污染全局变量:
import Promise from 'core-js-pure/actual/promise';
import Set from 'core-js-pure/actual/set';
import Iterator from 'core-js-pure/actual/iterator';
import from from 'core-js-pure/actual/array/from';
import flatMap from 'core-js-pure/actual/array/flat-map';
import structuredClone from 'core-js-pure/actual/structured-clone';
Promise.resolve(42).then(it => console.log(it));
// => 42
from(new Set([1, 2, 3]).union(new Set([3, 4, 5])));
// => [1, 2, 3, 4, 5]
flatMap([1, 2], it => [it, it]);
// => [1, 1, 2, 2]
Iterator.from(function * (i) { while (true) yield i++; }(1))
.drop(1).take(5)
.filter(it => it % 2)
.map(it => it ** 2)
.toArray();
// => [9, 25]
structuredClone(new Set([1, 2, 3]));
// => new Set([1, 2, 3])
目前Core-js的NPM周下载量稳定在34138K,Github上star超过21.7K,fork达到了1.6K,有超过13,642K的项目使用它,超过115+代码贡献者。
es5-shim
es5-shim.js 和 es5-shim.min.js 用来为 JavaScript 上下文打补丁以包含所有 EcmaScript 5 方法,这些方法可以用遗留 JavaScript 引擎模拟。 注意:由于 es5-shim.js 是为了给原生 Javascript 引擎打补丁,所以它应该是最先加载的库。
Array.prototype.every (standalone shim)
Array.prototype.filter (standalone shim)
Array.prototype.forEach (standalone shim)
Array.prototype.indexOf (standalone shim)
// 更多数组方法
Date.now
Date.prototype.toJSON
// 更多Date方法
Number.prototype.toExponential (standalone shim)
Number.prototype.toFixed
Number.prototype.toPrecision
// 更多Number方法
String.prototype.split (standalone shim)
String.prototype.trim (standalone shim)
String.prototype.lastIndexOf (standalone shim)
String.prototype.replace
// 更多String方法
Error.prototype.toString
Error.prototype.name
Error.prototype.message
// 更多Error方法
es5-sham.js 和 es5-sham.min.js 为 其他 ES5 方法打补丁,比如:
Object.create
Object.getPrototypeOf
Object.getOwnPropertyNames
Object.isSealed
Object.isFrozen
Object.isExtensible
Object.getOwnPropertyDescriptor
Object.defineProperty
// 更多其他方法
目的是为了允许将代码写入 ES5 而不会在旧引擎中导致运行时错误。 在许多情况下,这意味着这些打补丁的方法会导致许多 ES5 方法在低版本浏览器上默默地执行失败。 同时需要注意的是:es5-sham.js 需要 es5-shim.js 才能正常工作。
在浏览器项目中使用 ES 兼容性垫片的示例代码如下:
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.14/es5-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.14/es5-sham.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.5/es6-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.5/es6-sham.min.js"></script>
<script src="other-libs.js"></script>
目前es5-shim的NPM周下载量稳定在3443K,Github上star超过7.1K,fork达到了1K。
@babel/polyfill
Babel 默认只转换新的 JavaScript 句法,例如箭头函数、扩展运算符等,而不会转换新的 API,像是Set、Maps、Iterator、Generator 、Symbol、Reflect 等全局对象,以及一些定义在全局对象上的方法都不会进行转译。如果想使用这些新的对象和方法,则需要为当前环境提供一个 polyfill 垫片。
例如: ES6 在 Array 对象上有一个新增的 Array.from 方法,因为这个方法是全局对象上的方法,所以 Babel 就不会对这个方法进行转译。如果想让这个方法运行,就要使用 @babel/polyfill 为当前环境提供一个垫片。
需要首先安装:
npm install --save @babel/polyfil
安装好后就可以在程序入口文件的顶部引用 @babel/polyfil::
import '@babel/polyfill'
[].findIndex('babel')
babel-polyfill 解决了 Babel 不转换新 API 的问题,但是直接在代码中插入帮助函数,会导致污染了全局环境,并且不同的代码文件中包含重复的代码,导致编译后的代码体积变大。虽然这对于应用程序或命令行工具来说可能是好事,但如果已有代码打算提供给其他人使用的库,可能会有问题。
需要注意的是从 Babel 7.4.0 开始,不再推荐使用 @babel/polyfill 包,而是直接使用 core-js/stable 和 regenerator-runtime/runtime,如下所示:
import "core-js/stable";
import "regenerator-runtime/runtime";
目前@babel/polyfil的NPM周下载量稳定在1572K,Github上star超过42K,fork达到了5.6K,有超过8K的项目使用它。
es6-promise-polyfill
这是 ES6 Promise 的 polyfill,该实现基于 Jake Archibald 实现的 rsvp.js 子集。这个库的主要目标是:Promise实现应该与浏览器的原生实现保持一致,并且尽可能小。 所以它只是 ES6 Promise 规范的严格 polyfill,仅此而已。
它通过了 Promises/A+ 测试套件和 rsvp.js 测试套件,体积最小 2.6KB( 1KB+gzip)。默认使用setImmediate(如果可用),或者回退使用 setTimeout。
const Promise = require('es6-promise-polyfill').Promise;
const promise = new Promise(...);
或者使用CDN方式加载:
<script src="bower_components/es6-promise-polyfill/promise.min.js"></script>
<script>
var promise = new Promise(...);
</script>
目前es6-promise-polyfill的NPM周下载量稳定在32K。
es6-promise
这是 ES6 Promise 的 polyfill,实现是由 @jakearchibald 提取的 rsvp.js 的一个子集。使用这个库很简单,可以通过CDN的方式引入:
<!-- Automatically provides/replaces `Promise` if missing or broken. -->
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.js"></script>
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
<!-- Minified version of `es6-promise-auto` below. -->
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
或者直接使用模块化方法:
const Promise = require('es6-promise').Promise;
如果要填充全局环境(在 Node 中或通过 CommonJS 在浏览器中),请使用以下代码片段:
require('es6-promise').polyfill();
// 或者
require('es6-promise/auto');
请注意,上面代码没有将 polyfill() 的结果分配给任何变量, polyfill() 方法将在调用时自动修补全局环境(在本例中为 Promise 名称)。
目前es6-promise的NPM周下载量稳定在8000K,Github上star超过7.3K,fork达到了637+,有超过3008K的项目使用它。
promise-polyfill
用于浏览器和Node环境的轻量级 ES6 Promise polyfill, 严格遵守浏览器规范。 它是一个完美的 polyfill IE 或任何其他不支持原生Promise的浏览器。同时,promise-polyfill非常轻巧,压缩后 < 1kb 。
可以通过CDN方式引用:
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
以上代码执行时候,如果浏览器没有 window.Promise,将会自动设置一个全局 Promise 对象。如果本机 Promise 不存在时候,想添加一个全局 Promise 对象(Node或浏览器),也可以使用如下模块化方法:
import 'promise-polyfill/src/polyfill';
如果不想影响全局环境(有时称为 ponyfill),可以导入基本模块。
import Promise from 'promise-polyfill';
默认情况下,promise-polyfill 使用 setImmediate,如果不支持这个方法,则回退到 setTimeout 以异步执行。 因此,如果浏览器不支持 setImmediate(IE/Edge 是唯一支持 setImmediate 的浏览器),您可能会遇到性能问题。但是,可以使用 setImmediate polyfill 来解决这个问题。
import Promise from 'promise-polyfill/src/polyfill';
import setAsap from 'setasap';
Promise._immediateFn = setAsap;
目前promise-polyfill的NPM周下载量稳定在2338K,Github上star超过2.1K,fork达到了300+,有超过756K的项目使用它。
promise
这是 Promises 的简单实现,它是一组 ES6 Promises 的超集,旨在提供可读、高性能的代码,并仅提供当今使用 promises 绝对必要的扩展。
注意:Promise通过下划线 (_) 前缀属性公开内部结构。
可以通过CDN方式引用:
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/3.4.0/es5-shim.min.js"></script>
//请注意,es5-shim 必须在此库之前加载,以支持 IE9 之前的浏览器。
<script src="https://www.promisejs.org/polyfills/promise-6.1.0.js"></script>
或者也可以使用模块方法:
const Promise = require('promise');
const promise = new Promise(function (resolve, reject) {
get('http://www.google.com', function (err, res) {
if (err) reject(err);
else resolve(res);
});
});
promise库本身提供了诸如:Promise.resolve、Promise.reject、Promise.all、Promise.any、Promise.allSettled、Promise.denodeify、Promise.race等常见方法。比如下面是Promise.all的使用示例:
Promise.all([Promise.resolve('a'), 'b', Promise.resolve('c')])
.then(function (res) {
assert(res[0] === 'a')
assert(res[1] === 'b')
assert(res[2] === 'c')
})
目前promise的NPM周下载量稳定在11704K,Github上star超过2.5K,fork达到了310+,有超过9560K的项目使用它。
url-search-params-polyfill
这是 JavaScript 的 URLSearchParams 类的 polyfill 库。具有以下明显特征:
- 实现了 MDN 文档中的所有功能。
- 可用于浏览器和 Node.js环境
- 检测浏览器是否完全支持 URLSearchParams 并扩展它
- 兼容IE8及以上版本
可以通过如下方式导入使用:
import 'url-search-params-polyfill';
// Babel 和 ES2015+
require('url-search-params-polyfill');
//es5导入
开发者可以从字符串或对象实例化 URLSearchParams 的实例:
// new an empty object
var search1 = new URLSearchParams();
// from a string
var search2 = new URLSearchParams("id=1&from=home");
// from an object
var search3 = new URLSearchParams({ id: 1, from: "home" });
// from location.search, will remove first "?" automatically
var search4 = new URLSearchParams(window.location.search);
// from anther URLSearchParams object
var search5 = new URLSearchParams(search2);
// from a sequence
var search6 = new URLSearchParams([["foo", 1], ["bar", 2]]);
然后调用append、delete、get、getAll、has、set、toString、sort、forEach、keys、values、for..of等方法对URLSearchParams进行更改。
url-polyfill
Polyfill URL类 和 URLSearchParams类 以匹配最新的 WHATWG 规范。这个库在大多数用例中保持兼容,但不是 100%(如 unicode 字符、punycode 等),支持 IE 10+ 以上环境。
可以通过如下方式安装:
npm i url-polyfill --save
安装后即可在代码中直接使用:
const url = new URL('https://www.example.com/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0');
url.searchParams.append('page', 0);
console.log(url.toString()); // print: "https://www.example.com/?fr=yset_ie_syc_oracle&type=orcl_hpset&page=0#page0"
目前url-polyfill的NPM周下载量稳定在285K,Github上star超过300+,fork达到了60+。
util.promisify
Node版本 < v8 的 util.promisify 的 Polyfill,但是Node v8.0.0 已经添加了对内置 util.promisify 的支持,无需再使用这个库。
可以直接使用:
const promisify = require('util.promisify');
// Use `promisify` just like the built-in method on `util`
或者shim方式引入:
require('util.promisify/shim')();
// `util.promisify` is now defined
const util = require('util');
// Use `util.promisify`
这个包需要一个原生的 ES5 环境,并且 Promise 在全局范围内可用,否则会抛出错误。目前util.promisify的NPM周下载量稳定在13756K。
本文总结
本文主要和大家介绍 Polyfill是什么,前端最火的10大Polyfill,以及如何使用。因为篇幅有限,文章并没有就每一个Polyfill过多展开,如果有兴趣,可以直接在我主页继续阅读,但是文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!
参考资料
https://www.npmjs.com/package/core-js
https://www.npmjs.com/package/es5-shim
https://www.npmjs.com/package/babel-polyfill
https://www.npmjs.com/package/es6-promise
https://www.npmjs.com/package/promise-polyfill
https://www.npmjs.com/package/promise
https://www.npmjs.com/package/url-search-params-polyfill
https://www.npmjs.com/package/url-polyfill
https://www.npmjs.com/package/util.promisify
https://www.npmjs.com/package/es6-promise-polyfill
猜你喜欢
- 2024-09-10 Facebook发新版React,这些新功能让程序员直呼强大!
- 2024-09-10 React Native 网络层分析(react-native-router-flux)
- 2024-09-10 Brisk-Admin基于vue3+element-plus+vite开箱即用后台前端框架
- 2024-09-10 前端性能优化,你想知道的都在这里
- 2024-09-10 AngularJS2 教程—JavaScript 环境配置—架构大全第一章
- 2024-09-10 「免费开源」基于Vue和Quasar的动态表关系管理(六)
- 2024-09-10 2018年前端流行哪些技术?(推荐收藏)
- 2024-09-10 你还在用 for 循环遍历集合?试试 JavaScript 新增的 7 种方法吧!
- 2024-09-10 Vue开发中常用的ES6新特性(vue支持es几)
- 2024-09-10 在线编辑excel功能一次完整体验历程,以及可以避免的坑
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)