【IT168 编译】过去十年间,浏览器厂商和web性能专家大部分时间都在说本地存储(localStorage)很慢,web开发人员不应该再使用它了。
公平地说,说这话的人没有错。本地存储是一个同步API,它会阻塞主线程,任何时候访问它都会潜在地阻止页面的交互。
问题是本地存储API非常简单,而本地存储的唯一异步替代方案是IndexedDB,可实话说,后者的易用性或API并不受欢迎。
因此,开发人员只能在难以使用和不利于性能之间做出选择。虽然有一些库提供了本地存储 API的简单性,但实际上在底层使用异步存储API,包括应用程序中的这些库之一,会有一个文件大小的开销,并会影响性能预算。
但是,如果可以使用本地存储 API的简单性获得异步存储API的性能,而不需要付出文件大小的成本,情况会怎样呢?
嗯,也许很快就会有。Chrome正在试验一项名为内置模块的新功能,我们计划推出的第一个功能是名为KV 存储的异步键/值存储模块。
但在详细介绍KV存储模块之前,让我先解释一下内置模块的含义。
什么是内置模块?
内置模块就像普通的JavaScript模块一样,只是它们不需要下载,因为它们是随浏览器一起发布的。
与传统web API一样,内置模块也必须经过标准化过程——每个模块都有自己的规范,在发布之前需要进行设计审查,并得到web开发人员和其他浏览器供应商的积极支持。
与传统web api不同,内置模块不公开在全局范围内——它们只能通过导入来使用。
不全局公开内置模块有很多好处:它们不会为启动一个新的JavaScript运行时环境增加任何额外负担 (例如,一个新的tab、worker或service worker),而且它们不会消耗任何内存或CPU,除非它们确实被导入了。此外,它们不会产生与代码中定义的其他变量命名发生冲突的风险。
要导入内置模块,可以使用前缀std:后面加上内置模块的标识符。例如,在受支持的浏览器中,可以使用以下代码导入KV存储模块(有关如何在不受支持的浏览器中使用KV存储polyfill,请参阅此网页https://developers.google.com/web/updates/2019/03/kv-storage#what_if_a_browser_doesnt_support_a_built-in_module):
KV存储模块
KV存储模块的简单性类似于本地存储 API,但是它的API形状实际上更接近于JavaScript映射。它不是getItem()、setItem()和removeItem(),而是get()、set()和delete()。它还有其他类似于Map的方法,但本地存储无法使用,比如keys()、values()和entries(),而且与Map一样,它的键不必是字符串,它们可以是任何结构化序列化类型。
与Map不同,所有KV存储方法都返回promise或async迭代器(因为与localStorage相比,这个模块的主要特点是它不是同步的)。要详细了解完整的API,可以参考规范https://wicg.github.io/kv-storage/#storagearea。
正如您可能从上面的代码示例中注意到的,KV存储模块有两个命名导出:Storage和StorageArea。
Storage是命名为“default”的StorageArea类的一个实例,开发人员将在应用程序代码中最经常使用它。StorageArea类用于需要额外隔离的情况(例如,存储数据并希望避免与通过默认存储实例存储的数据发生冲突的第三方库)。StorageArea数据存储在名为kv-storage:${name}的IndexedDB数据库中,其中name是StorageArea实例的名称。
以下是如何在你的代码中使用KV存储模块的例子:
注意: KV存储模块目前可以在Chrome 74中使用,如果您打开了实验性web平台特性标志的话(Chrome://flags/#enable-experimental-web-platform-features)。
如果浏览器不支持内置模块怎么办?
如果您熟悉在浏览器中使用本机JavaScript模块,那么您可能知道(至少到目前为止)导入URL以外的任何内容都会生成错误。std:kv-storage不是一个有效的URL。
这就提出了一个问题:我们是否必须等到所有浏览器都支持内置模块后才能在代码中使用它吗?谢天谢地,答案是否定的。
实际上,只要有一个浏览器支持内置模块,您就可以使用它们,这得益于我们正在试验的另一个特性导入映射(import map)的帮助。
导入映射
导入映射本质上是一种机制,通过这种机制,开发人员可以将导入标识符化名为一个或多个替代标识符。
这非常强大,因为它提供了一种方法来更改(在运行时)浏览器在整个应用程序中解析特定导入标识符的方式。
对于内置模块,这允许您在应用程序代码中引用模块的polyfill,但是支持内置模块的浏览器可以加载该版本。
下面是如何声明导入映射,使其与KV存储模块一起工作:
面代码中的关键点是URL /path/to/kv-storage-polyfill.mjs被映射到两个不同的资源:std:kv-storage和原始URL /path/to/kv-storage-polyfill.mjs。
因此,当浏览器遇到引用该URL (/path/to/kv-storage-polyfill.mjs)的导入语句时,它首先尝试加载std:kv-storage,如果无法加载,则返回到加载/path/to/kv-storage-polyfill.mjs。
同样,这里的神奇之处在于,浏览器不需要支持导入映射或内置模块来实现这种技术,因为传递给导入语句的URL是polyfill的URL。polyfill实际上不是一个回退,它是默认值。内置模块是渐进式的增强。
那么根本不支持模块的浏览器呢?
为了使用导入映射有条件地加载内置模块,您必须实际使用导入语句,这也意味着您必须使用模块脚本,即<script type="module">。
目前,超过80%的浏览器支持模块,对于不支持模块的浏览器,可以使用module/nomodule技术为旧浏览器提供遗留包。注意,在生成nomodule构造时,需要包含所有的polyfills,因为不支持模块的浏览器肯定不支持内置模块。
KV存储演示
为了说明在仍然支持旧浏览器的情况下使用内置模块是可能的,我将上面描述的所有技术整合在一起,并在今天的所有浏览器中运行:
·支持模块、导入映射和内置模块的浏览器不会加载任何不需要的代码。
·支持模块和导入映射但不支持内置模块的浏览器加载KV存储polyfill(通过浏览器的模块加载器)。
·支持模块但不支持导入映射的浏览器也加载KV存储polyfill(通过浏览器的模块加载器)
·完全不支持模块的浏览器在其遗留包中获得KV存储polyfill(通过加载 <script nomodule>)。
演示程序托管在Glitch上,所以您可以查看它的源代码(https://glitch.com/edit/#!/rollup-built-in-modules)。我在README中(https://glitch.com/edit/#!/rollup-built-in-modules?path=README.md)也有一个详细的解释实。如果你好奇它是如何构建的,请随意查看。
注意:演示使用Rollup捆绑应用程序代码和polyfill,并生成使其跨浏览器工作所需的各种版本。我想用webpack做一个类似的演示,但是它目前不支持模块输出格式,所以这还不可能。
为了实际看到本机内置模块的运行情况,您必须在Chrome 74(当前是Chrome Dev或Canary)中加载演示程序,并打开实验性web平台特性标志(Chrome://flags/#enable-experimental-web-platform-features)。
您可以验证内置模块正在加载,因为您不会在DevTools的源面板中看到polyfill脚本;相反,您将看到内置模块版本(有趣的事实:您可以实际检查模块的源代码,甚至在其中添加断点。):
请给我们反馈
本介绍应该让您初步了解了内置模块的功能。希望你很兴奋!我们非常希望开发人员能够尝试KV存储模块(以及这里讨论的所有新特性)并给我们反馈。
下面是GitHub的链接,你可以在这里对本文中提到的每个特性给出反馈:
KV存储(https://github.com/WICG/kv-storage)
KV存储Polyfill(https://github.com/GoogleChromeLabs/kv-storage-polyfill)
内置模块(https://github.com/tc39/proposal-javascript-standard-library)
导入映射(https://github.com/WICG/import-maps)
如果您的站点当前使用本地存储,您应该尝试切换到KV存储 API,看看它是否能满足您的所有需求。如果你报名参加KV存储初始试验(https://developers.chrome.com/origintrials/#/trials/active),你今天就可以部署这些功能。所有用户都应该从更好的存储性能中受益,Chrome 74+用户无需支付任何额外的下载成本。
原文作者:Philip Walton,谷歌Web平台工程师 来源:谷歌
原文链接:https://developers.google.com/web/updates/2019/03/kv-storage