什么是polyfill

374 阅读4分钟

几周前,我在IE上发现了一个错误,用户看到的只是一个空白的白色页面。如果你已经在客户端SPA的奇妙世界里呆了一段时间,你可能不用想就知道是什么问题。这就对了。这是在客户端渲染发生之前的一个JavaScript错误。

考虑到这个错误只在Internet Explorer中出现,我的第一个猜测是polyfills的问题。是的!就是这个问题!

Uncaught TypeError: contacts.includes is not a function

但我们是用Babel转译我们的代码的!这难道不意味着我可以使用所有我想要的最新和最伟大的JavaScript,而不必担心浏览器是否支持它?不,不是的。让我们了解一下...

由于TC39内部和周围人们的努力,JavaScript在不断地发展。一些演变依赖于新的语法(如箭头函数),这使我能够做到这一点:

const addOne = num => num + 1
if (addOne(2) > 2) {
  console.log('Math. Wow!')
}

通常,我们可以在我们的源代码中使用这种语法,只要我们把它转换成可以在浏览器中运行的语法(例如,通过使用转置器,如babel例子在浏览器中用babel-preset-env转置)。

其他一些新的功能依赖于新的API,比如Array.prototype.includes ,它允许我这样做。

const contacts = ['Brooke', 'Becca', 'Nathan', 'Adam', 'Michael']
if (contacts.includes('Rachel')) {
  console.log('You have a Rachel!')
}

有了这些,如果你通过babel的env预设运行它们includes 函数就不会被转置,因为这不是一个语法问题,而是一个内置的API问题,而babel的env预设只包括语法转换的转换。你可以 写你自己的babel插件(像这样)来转换代码,但对于某些API来说,这是不现实的,因为转换后的版本会非常复杂。

polyfill是一种代码,它将使当前运行的JavaScript环境支持它所不支持的功能。例如,一个用于includes 的(不完美的)polyfill可能看起来像这样关于真正的polyfill,请参考MDN)。

if (!Array.prototype.includes) {
  Array.prototype.includes = function includes(searchElement) {
    return this.indexOf(searchElement) !== -1
  }
}

if 语句的存在是为了使其成为一个 "门控 "的polyfill。这意味着,如果功能已经存在,polyfill代码将不会覆盖预先存在的行为。String.prototype 你可能认为这是可取的,但这实际上是includes不被称为contains 的原因(TL;DR:一些版本的mootools以门控方式实现了contains ,但实现方式与includes 的工作方式不同,所以TC39不得不改变名称以避免破坏大量网站)。

Array.prototype.includes 赋予一个函数的部分被称为 "monkey-patching"🐒通过将其应用于原型,我们为应用中的所有数组添加了includes 支持(在这里了解更多关于原型的信息)。有效地,polyfill的工作是使我能够使用JavaScript功能,而不必担心我的代码运行环境是否支持它(例如IE 10)。

对于语法转换,我推荐babel-preset-env。它实际上是相当简单的。对于polyfills,最流行的是 core-js.你也可以看一下 babel-polyfill它使用core-js 和一个自定义的regenerator runtime ,以支持生成器和async/await的方式,babel转置它。Polyfills有时被称为 "垫片",你可能会对 js-shims你可能对airbnb的Polyfills感兴趣(我被告知它比core-js 更符合规范)。

那么,我做了什么来修复我的IE10错误?好吧,有一件事让我很不爽,那就是我必须把所有这些用于polyfills的代码运送到所有的浏览器,即使它们确实支持这些功能。但几年前,我听说有一种服务,能够运送只与请求它们的浏览器有关的polyfills。我创建了自己的端点,使用了支持该服务的模块,我将在下周写下这篇文章

我希望这对你有帮助!祝您好运!

P.S. 你可能听说过一种叫做 "ponyfill "的东西。Ponyfills与polyfills类似,只是它们不做猴子补丁,而只是函数本身,允许你直接调用它们。了解更多关于ponyfills的信息。总的来说,我更赞成ponyfills,尽管你不能完全摆脱polyfills,因为你的依赖常常依赖于你的浏览器不支持的内置程序。