polyfill

在es6风靡的时候,babel给了我们一个有力的转换方案,可以在低版本浏览器上写一些新语法而不用考虑兼容问题

polyfill的诞生

语法和API区分

语法是用来产生特殊效果的一些符号

list = [...list]

API分为对象静态、实例方法和函数

这里我们简单区分一下,方便下面展开

babel的局限

为什么会出现polyfill呢,我们都知道,babel是生成AST,然后暴露了AST操作接口插件给我们,AST看起来是一个神秘的东西,但是我们可以大概知道,它是基于当前信息生成了一个代码的另外一个表现形式,但是由于js是动态的,我们是无法得知一个实例调用的方法到底是哪个原型的,这一点就导致了后续产生了很多polyfill的方案,当然一些特殊的语法支持,也需要polyfill

a.includes(x)  // 这里是string还是array呢,我们无法得知

由于上述特性,处理API的编译,尤其困难

实验配置(babel、webpack)

babel

npm i -D  @babel/core @babel/preset-env

npm i @babel/polyfill

.babelrc

{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "entry",
"corejs": 2
}]
]
}

webpack

安装

npm i -D webpack webpack-cli

npm i babel-loader

配置

webpack.config.js

const path = require('path');
module.exports = {
// 开发模式,能看到未压缩的代码
mode: "development",
// 编译入口
entry: './src/index.js',
// 编译出口
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
// 编译规则
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
// 配置babel
loader: 'babel-loader'
}
}
]
}
};

配置脚本

polyfill方案

polyfill的核心就是检测当前是否存在该方法,不存在才使用我们的实现

手动

不推荐

缺点:

非官方实现,很容易出现于规范不一致导致的问题,一些polyfill实现起来也很麻烦,仅用于临时一些修复

if (!Array.prototype.includes) {
Array.prototype.includes = function () {
// 实现
}
}

官方polyfill

babel提供了一个@babel/polyfill包,包括了目前所有的polyfill

以下都基于了新的presets,env的useBuiltIns选项测试

// .babelrc 

{
"presets": [
["@babel/preset-env", {
// "useBuiltIns": "xxx",
}]
]
}

全部导入(entry)

一次性全部导入整个polyfill,是一个彻底的方案

优点:

方便

缺点:

文件很大,所以后续的方案都是针对这个问题做的优化

// .babelrc 

{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "entry",
}]
]
}

我们在webpack主入口导入polyfill

运行npm run start

可以看到完全导入polyfill,打包后的文件增加了400K,polyfill未压缩文件在250K左右,这里有webpack的其他因素影响,但是后续测试也在此条件下进行,可以忽略

entry选项可以支持配置browserlist配置编译目标环境,从而减少编译的代码体积

按需导入(usage)

可以按照我们项目中使用的API,只导入这部分polyfill,同时配合browserlist可以实现代码按需加载同时为运行环境按需加载

优点:

配置方便

体积很少

缺点:

还是没有根据运行环境polyfill,导致所有运行环境被一致polyfill,稍微有点浪费,比如说同时要求IE和谷歌,他们最后的polyfill集合是两者的并集,而不是分开打包的。

使用方法

  1. 去掉我们index.js的import "@babel/polyfill"

  2. useBuiltIns配置改为usage

效果

注意点

browserslist虽然可以按照指定环境检测是否需要polyfill,但是由于其源是can i use上的,其实还是不太精准的,js的polyfill比起css、html的polyfill要求更高,这是一个值得考虑的问题,不过,vue-cli官方采用了这个方案@vue/babel-preset-app,这是基于useBuiltIns: 'usage'和browserslist结合进行polyfill的一个方案

警告

由于babel不会编译node_modules下的包,所以这些依赖如果使用了新特性,此方案不会编译其新语法,一个处理方式就是显式添加polyfill,另外一种方式就是你不知道第三方依赖用了什么,这个时候需要回退到useBuiltIns: 'entry'

UA检测 polyfill

我们可以根据我们使用的新特性传输给服务器,然后服务器检测浏览器的UA,就可以决定真正返回的polyfill了,这个思路实现了真正的环境按需polyfill,不像browserslist一样会取所有兼容环境的并集。

优点:

能够真正按照运行环境进行polyfill

缺点

多一次http请求

UA标志混乱,很可能导致Polyfill缺失

增加服务区成本

polyfill.io

用法

<script src="https://polyfill.io/v3/polyfill.min.js?></script>

非常简单,导入一个cdn即可,但是这个服务是在国外,所以非常慢

阿里fork了它的开源服务,做了如下定制

将polyfill包进行拆分,加入了polyfill.io不认可但是工程需要的polyfill比如说RegeneratorRuntime

编写了标准的UA识别逻辑,大幅大幅降低了响应时间 通常响应时间在 30ms 以内

利用CDN提提供了高可用性的服务

阿里polyfill

https://polyfill.alicdn.com/polyfill.min.js

这个polyfill被正式用到阿里巴巴官方,前几天有看过这个script,最近好像更新为其他的了

polyfill未来

按需特性探测

我们在编码时,工具可以探测源码及node_modules下使用到的特性,返回一个特性列表

在线补丁

就像https://polyfill.io/的方案,我们会检测按需特性探测得到的列表是否在浏览器已经支持,只下载缺失的polyfill

按需特性探测 + 在线补丁才是终极方案

polyfill目前的最佳实践

目前在线补丁这方面还未成熟,我们暂时不使用在这部分,只对按需特性探测进行优化

useBuiltIns: 'usage'和browserslist结合

这里我们对这个方案进行一个优化

不编译第三方包的处理

1.第三方包明确指出了需要的 polyfill

只需要加此polyfill显式加入include配置中去,具体配置可以看文档

2.没有指出需要的polyfill

这个情况暂时没有办法处理,需要回退到useBuiltIns: 'entry'配置

转译API的另外一种方式

优点

1.不会造成全局污染

缺点

1.由于避免全局污染是由助手函数实现的,所以体积会比正常polyfill大

2.暂时不支持[].inclues这样的实例方法

polyfill的问题

polyfill是会污染原型的

if (!Array.prototype.includes) {
Array.prototype.includes = function () {
// 实现
}
}

如果是开发一个组件库,就不能污染原型,因为会导致环境出现一些不可预测的问题

@babel/plugin-transform-runtime

用法

安装

npm install --save-dev @babel/plugin-transform-runtime

npm install --save @babel/runtime

配置

{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}

runtime完成的工作

  • 在开启regenerator选项时,自动引入@babel/runtime/regenerator

  • 可以通过corejs定制版本

  • 开启helpers选项,会将内联函数提取为helper函数,统一引入

总结

如果时开发组件库等第三方依赖时,采用babel-runtime机制来实现我们代码的转译,避免对运行环境的污染,在开发应用时,使用正常的polyfill

polyfll方案优化的更多相关文章

  1. 项目四:Java秒杀系统方案优化-高性能高并发实战

    技术栈 前端:Thymeleaf.Bootstrap.JQuery 后端:SpringBoot.JSR303.MyBatis 中间件:RabbitMQ.Redis.Druid 功能模块 分布式会话,商 ...

  2. Devops 开发运维高级篇之Jenkins+Docker+SpringCloud微服务持续集成——部署方案优化

    Devops 开发运维高级篇之Jenkins+Docker+SpringCloud微服务持续集成--部署方案优化 之前我们做的方案部署都是只能选择一个微服务部署并只有一台生产服务器,每个微服务只有一个 ...

  3. C#编程实践–产假方案优化版

    前言 既然作为一个踏踏实实学习技术的人,就要有一颗谦卑.虚心和追求卓越的心,我不能一次就写出很完美的代码,但我相信,踏踏实实一步一步的优化,代码就可以变得趋近完美,至少在某一个特定场景下相对完美,这和 ...

  4. SSD阵列卡方案优化:考虑使用RAID 50替代RAID 10

    最近一直在研究RAID 50,因为牺牲一半的容量的RAID 10代价实在太大了,而且它提供的可用性也并不是百分百的,我们首先来看下RAID 10的可用性分析: 以同等容量的不同RAID方式作为案例分析 ...

  5. 《React-Native系列》44、基于多个TextInput的键盘遮挡处理方案优化

    曾经写过两篇关于在ReactNative上处理键盘遮挡输入表单TextInput的情况.建议读者能够先看看 1.<React-Native系列>33. 键盘遮挡问题处理 2.<Rea ...

  6. Java秒杀系统方案优化 高性能高并发实战(已完成)

    1:商品列表 2:商品详情判断是否可以开始秒杀,未开始不显示秒杀按钮显示倒计时,开始显示秒杀按钮,同时会显示验证码输入框以及验证码图片,当点击秒杀按钮的时候会首先判断验证码是否正确,如果正确会返回一个 ...

  7. Java秒杀系统方案优化 高性能高并发实战(1)

    首先先把 springboot +thymeleaf 搞起来 ,参考 springboot 官方文档 本次学习 使用 springboot + thymeleaf+mybatis+redis+Rabb ...

  8. Authentication 方案优化探索(JWT, Session, Refresh Token, etc.)

    转载自:http://www.jianshu.com/p/5ac8a0e1e5a8

  9. 全面解密QQ红包技术方案:架构、技术实现、移动端优化、创新玩法等

    本文来自腾讯QQ技术团队工程师许灵锋.周海发的技术分享. 一.引言 自 2015 年春节以来,QQ 春节红包经历了企业红包(2015 年).刷一刷红包(2016 年)和 AR 红包(2017 年)几个 ...

随机推荐

  1. 职位画像分析(pandas/ matplotlib)

    一.数据分析的步骤 二.提出问题 (1) 分析数据分析师主要的技能排名? (2) 分析数据分析师薪资和岗位地点.学历.工作年限的关系? (3) 数据分析师的学历需求? (4) 不同城市数据分析师的需求 ...

  2. yii2关联表

    asArray()这个方法很好用,返回数组是1版本想要的形式,这种方式有种tp框架的感觉

  3. Luogu P3600 随机数生成器

    Luogu P3600 随机数生成器 题目描述 sol研发了一个神奇的随机数系统,可以自动按照环境噪音生成真·随机数. 现在sol打算生成\(n\)个\([1,x]\)的整数\(a_1...a_n\) ...

  4. linux 安装 nvm, node.js, npm

    vscode在wsl中开发node应用,如何安装nvm? git clone git@github.com:nvm-sh/nvm.git ~/.nvm 设置淘宝registry npm config ...

  5. 下载文件旁边附的MD5/SHA256等有什么用途?

    在我们下载很多软件时,旁边会出现md5,sha1/sha256/sha512等一长串字符串,这些字符串是什么意义呢? 因为怕盗版或者怕软件被植入病毒或者插件等,要对软件的完整性做校验.步骤:先下载完软 ...

  6. 全栈工程师对Python面试中is和==区别的详细解说!看完真的学到了!

    面试实习生的时候,当问到 is 和 == 的区别时,很多同学都答不上来,搞不清两者什么时候返回一致,什么时候返回不一致.本文我们来看一下这两者的区别. 我们先来看几个例子: a = "hel ...

  7. Define the Data Model and Set the Initial Data 定义数据模型并设置初始数据

    This topic describes how to define the business model and the business logic for WinForms and ASP.NE ...

  8. window启动webpack打包的三种方法

    1.在cmd终端执行 npx webpack命令 2.在package.json文件同级建立webpack.config.js文件,内容如下: const path = require('path') ...

  9. Android开发当中的JavaBean实现

    一般我们在Android开发当中如果会对一些数据类进行解析,那么则需要写出一个JavaBean的类,比如在进行json解析的时候,就需要使用这个类进行数据的处理,下面是我们的JavaBean的模板代码 ...

  10. Tomcat启动分析(二)-自己编译Tomcat

    为了方便分析Tomcat源码,利用大家习惯的方式来进行Debug调试,那么如何将Tomcat源码导入到Eclipse呢,这就是本文的重点 1 准备 1.1 获取Tomcat源码 获取tomcat源码有 ...