corejs放弃开源!细数前端10百万级热门Polyfill
大家好,很高兴又见面了,我是高级前端进阶,由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
高级前端进阶
前不久关于corejs作者的事情在科技圈闹得沸沸扬扬,具体可以阅读我的文章《前端地震!corejs作者放弃开源?》,今天将带着大家一起细数前端周均下载百万、甚至千万级别的Polyfill。话不多说,直接开始!什么是polyfill?
polyfill是通过修补API来添加缺失功能的代码,典型的例子是通过polyfill在旧浏览器中添加新功能。例如,Modernizr检测浏览器功能并使用一组polyfill来启用旧浏览器中的浏览器功能,或者提供尚不支持的功能的补丁。
下面代码是笔者用于处理Android4。4以下浏览器webview不支持部分功能的代码,分别添加了urlpolyfill(可以使用newURL)、babelpolyfill、es5shim(部分代码兼容)这3个polyfill:!urlpolyfill。min。js!babelpolyfill6。26。0polyfill。min。js!es5shim4。6。7es5shim。min。js
这种解决方案的问题是:因为它们是修补缺失的API方法,所以特点是污染全局作用域。至于如何解决,以前写过一篇文章《前端Polyfill、Ponyfill、Prollyfill傻傻分不清楚?》单独论述过,本文将重点关注在前端的热门polyfill上。corejs
什么是corejs?
Corejs是JavaScript的模块化标准库。包括ECMAScript的Polyfill到ES2023,主要囊括:Promise、Symbol、Collections、Iterators、TypedArrays,、类型数组以及诸多其他特性、ECMAScript提案、一些跨平台的WHATWGW3C特性和提案等等。
将上面的简短介绍拆开来看,主要包括以下核心特性:Corejs是JavaScript标准库中最流行和最通用的polyfill:它为最新的ECMAScript标准和提案提供支持,从古老的ES5功能到迭代器等前沿功能,以及与ECMAScript密切相关的Web平台功能,如structuredClone等等。Corejs是最复杂和最全面的polyfill项目:corejs包含大约5000个复杂程度不同的polyfill模块(NPM文件数量显示为3331),从Object。hasOwn或Array。prototype。at到URL、Promise或Symbol等等。Corejs最大限度地模块化:可以允许开发者仅加载需要的功能,而且可以不污染全局命名空间。Corejs不是一个框架,其专为与工具集成而设计,并提供了为此所需的一切。例如:babelpolyfill、babelpresetenv、babeltransformruntime,类似的SWC功能都基于corejs,而且最重要的是开发无感,开箱即用。
比如通过如下方式引入corejs将不会污染全局变量:importPromisefromcorejspureactualpromise;importSetfromcorejspureactualset;importIteratorfromcorejspureactualiterator;importfromfromcorejspureactualarrayfrom;importflatMapfromcorejspureactualarrayflatmap;importstructuredClonefromcorejspureactualstructuredclone;Promise。resolve(42)。then(itconsole。log(it));42from(newSet(〔1,2,3〕)。union(newSet(〔3,4,5〕)));〔1,2,3,4,5〕flatMap(〔1,2〕,it〔it,it〕);〔1,1,2,2〕Iterator。from(function(i){while(true)yieldi;}(1))。drop(1)。take(5)。filter(itit2)。map(itit2)。toArray();〔9,25〕structuredClone(newSet(〔1,2,3〕));newSet(〔1,2,3〕)
目前Corejs的NPM周下载量稳定在34138K,Github上star超过21。7K,fork达到了1。6K,有超过13,642K的项目使用它,超过115代码贡献者。es5shim
es5shim。js和es5shim。min。js用来为JavaScript上下文打补丁以包含所有EcmaScript5方法,这些方法可以用遗留JavaScript引擎模拟。注意:由于es5shim。js是为了给原生Javascript引擎打补丁,所以它应该是最先加载的库。Array。prototype。every(standaloneshim)Array。prototype。filter(standaloneshim)Array。prototype。forEach(standaloneshim)Array。prototype。indexOf(standaloneshim)更多数组方法Date。nowDate。prototype。toJSON更多Date方法Number。prototype。toExponential(standaloneshim)Number。prototype。toFixedNumber。prototype。toPrecision更多Number方法String。prototype。split(standaloneshim)String。prototype。trim(standaloneshim)String。prototype。lastIndexOf(standaloneshim)String。prototype。replace更多String方法Error。prototype。toStringError。prototype。nameError。prototype。message更多Error方法
es5sham。js和es5sham。min。js为其他ES5方法打补丁,比如:Object。createObject。getPrototypeOfObject。getOwnPropertyNamesObject。isSealedObject。isFrozenObject。isExtensibleObject。getOwnPropertyDescriptorObject。defineProperty更多其他方法
目的是为了允许将代码写入ES5而不会在旧引擎中导致运行时错误。在许多情况下,这意味着这些打补丁的方法会导致许多ES5方法在低版本浏览器上默默地执行失败。同时需要注意的是:es5sham。js需要es5shim。js才能正常工作。
在浏览器项目中使用ES兼容性垫片的示例代码如下:
目前es5shim的NPM周下载量稳定在3443K,Github上star超过7。1K,fork达到了1K。babelpolyfill
Babel默认只转换新的JavaScript句法,例如箭头函数、扩展运算符等,而不会转换新的API,像是Set、Maps、Iterator、Generator、Symbol、Reflect等全局对象,以及一些定义在全局对象上的方法都不会进行转译。如果想使用这些新的对象和方法,则需要为当前环境提供一个polyfill垫片。
例如:ES6在Array对象上有一个新增的Array。from方法,因为这个方法是全局对象上的方法,所以Babel就不会对这个方法进行转译。如果想让这个方法运行,就要使用babelpolyfill为当前环境提供一个垫片。
需要首先安装:npminstallsavebabelpolyfil
安装好后就可以在程序入口文件的顶部引用babelpolyfil::importbabelpolyfill〔〕。findIndex(babel)
babelpolyfill解决了Babel不转换新API的问题,但是直接在代码中插入帮助函数,会导致污染了全局环境,并且不同的代码文件中包含重复的代码,导致编译后的代码体积变大。虽然这对于应用程序或命令行工具来说可能是好事,但如果已有代码打算提供给其他人使用的库,可能会有问题。
需要注意的是从Babel7。4。0开始,不再推荐使用babelpolyfill包,而是直接使用corejsstable和regeneratorruntimeruntime,如下所示:importcorejsstable;importregeneratorruntimeruntime;
目前babelpolyfil的NPM周下载量稳定在1572K,Github上star超过42K,fork达到了5。6K,有超过8K的项目使用它。es6promisepolyfill
这是ES6Promise的polyfill,该实现基于JakeArchibald实现的rsvp。js子集。这个库的主要目标是:Promise实现应该与浏览器的原生实现保持一致,并且尽可能小。所以它只是ES6Promise规范的严格polyfill,仅此而已。
它通过了PromisesA测试套件和rsvp。js测试套件,体积最小2。6KB(1KBgzip)。默认使用setImmediate(如果可用),或者回退使用setTimeout。constPromiserequire(es6promisepolyfill)。Promise;constpromisenewPromise(。。。);
或者使用CDN方式加载:
目前es6promisepolyfill的NPM周下载量稳定在32K。es6promise
这是ES6Promise的polyfill,实现是由jakearchibald提取的rsvp。js的一个子集。使用这个库很简单,可以通过CDN的方式引入:!AutomaticallyprovidesreplacesPromiseifmissingorbroken。!Minifiedversionofes6promiseautobelow。
或者直接使用模块化方法:constPromiserequire(es6promise)。Promise;
如果要填充全局环境(在Node中或通过CommonJS在浏览器中),请使用以下代码片段:require(es6promise)。polyfill();或者require(es6promiseauto);
请注意,上面代码没有将polyfill()的结果分配给任何变量,polyfill()方法将在调用时自动修补全局环境(在本例中为Promise名称)。
目前es6promise的NPM周下载量稳定在8000K,Github上star超过7。3K,fork达到了637,有超过3008K的项目使用它。promisepolyfill
用于浏览器和Node环境的轻量级ES6Promisepolyfill,严格遵守浏览器规范。它是一个完美的polyfillIE或任何其他不支持原生Promise的浏览器。同时,promisepolyfill非常轻巧,压缩后1kb。
可以通过CDN方式引用:
以上代码执行时候,如果浏览器没有window。Promise,将会自动设置一个全局Promise对象。如果本机Promise不存在时候,想添加一个全局Promise对象(Node或浏览器),也可以使用如下模块化方法:importpromisepolyfillsrcpolyfill;
如果不想影响全局环境(有时称为ponyfill),可以导入基本模块。importPromisefrompromisepolyfill;
默认情况下,promisepolyfill使用setImmediate,如果不支持这个方法,则回退到setTimeout以异步执行。因此,如果浏览器不支持setImmediate(IEEdge是唯一支持setImmediate的浏览器),您可能会遇到性能问题。但是,可以使用setImmediatepolyfill来解决这个问题。importPromisefrompromisepolyfillsrcpolyfill;importsetAsapfromsetasap;Promise。immediateFnsetAsap;
目前promisepolyfill的NPM周下载量稳定在2338K,Github上star超过2。1K,fork达到了300,有超过756K的项目使用它。promise
这是Promises的简单实现,它是一组ES6Promises的超集,旨在提供可读、高性能的代码,并仅提供当今使用promises绝对必要的扩展。
注意:Promise通过下划线()前缀属性公开内部结构。
可以通过CDN方式引用:请注意,es5shim必须在此库之前加载,以支持IE9之前的浏览器。
或者也可以使用模块方法:constPromiserequire(promise);constpromisenewPromise(function(resolve,reject){get(http:www。google。com,function(err,res){if(err)reject(err);elseresolve(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的项目使用它。urlsearchparamspolyfill
这是JavaScript的URLSearchParams类的polyfill库。具有以下明显特征:实现了MDN文档中的所有功能。可用于浏览器和Node。js环境检测浏览器是否完全支持URLSearchParams并扩展它兼容IE8及以上版本
可以通过如下方式导入使用:importurlsearchparamspolyfill;Babel和ES2015require(urlsearchparamspolyfill);es5导入
开发者可以从字符串或对象实例化URLSearchParams的实例:newanemptyobjectvarsearch1newURLSearchParams();fromastringvarsearch2newURLSearchParams(id1fromhome);fromanobjectvarsearch3newURLSearchParams({id:1,from:home});fromlocation。search,willremovefirst?automaticallyvarsearch4newURLSearchParams(window。location。search);fromantherURLSearchParamsobjectvarsearch5newURLSearchParams(search2);fromasequencevarsearch6newURLSearchParams(〔〔foo,1〕,〔bar,2〕〕);
然后调用append、delete、get、getAll、has、set、toString、sort、forEach、keys、values、for。。of等方法对URLSearchParams进行更改。urlpolyfill
PolyfillURL类和URLSearchParams类以匹配最新的WHATWG规范。这个库在大多数用例中保持兼容,但不是100(如unicode字符、punycode等),支持IE10以上环境。
可以通过如下方式安装:npmiurlpolyfillsave
安装后即可在代码中直接使用:consturlnewURL(https:www。example。com?frysetiesycoracletypeorclhpsetpage0);url。searchParams。append(page,0);console。log(url。toString());print:https:www。example。com?frysetiesycoracletypeorclhpsetpage0page0
目前urlpolyfill的NPM周下载量稳定在285K,Github上star超过300,fork达到了60。util。promisify
Node版本v8的util。promisify的Polyfill,但是Nodev8。0。0已经添加了对内置util。promisify的支持,无需再使用这个库。
可以直接使用:constpromisifyrequire(util。promisify);Usepromisifyjustlikethebuiltinmethodonutil
或者shim方式引入:require(util。promisifyshim)();util。promisifyisnowdefinedconstutilrequire(util);Useutil。promisify
这个包需要一个原生的ES5环境,并且Promise在全局范围内可用,否则会抛出错误。目前util。promisify的NPM周下载量稳定在13756K。本文总结
本文主要和大家介绍Polyfill是什么,前端最火的10大Polyfill,以及如何使用。因为篇幅有限,文章并没有就每一个Polyfill过多展开,如果有兴趣,可以直接在我主页继续阅读,但是文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!
参考资料
https:www。npmjs。compackagecorejs
https:www。npmjs。compackagees5shim
https:www。npmjs。compackagebabelpolyfill
https:www。npmjs。compackagees6promise
https:www。npmjs。compackagepromisepolyfill
https:www。npmjs。compackagepromise
https:www。npmjs。compackageurlsearchparamspolyfill
https:www。npmjs。compackageurlpolyfill
https:www。npmjs。compackageutil。promisify
https:www。npmjs。compackagees6promisepolyfill