javascript - 当脚本加载为 "preload"/"modulepreload"时会发生什么?

标签 javascript web-worker es6-modules

web.dev 上有一篇非常有趣的文章,关于 module worker 的 https://web.dev/module-workers/我们可以将 worker 加载为预加载模块,这意味着它们可以被预加载,甚至可以预解析和预取它们的依赖项 (https://web.dev/module-workers/#preload-workers-with-modulepreload)。
如果我是正确的,不仅 Web-Workers 可以作为预加载模块加载,这适用于任何 js 脚本、字体、css 等,例如

<link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">

<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">
有一个在这篇文章中,这让我很困扰:

Preloaded modules can also be used by both the main thread and module workers. This is useful for modules that are imported in both contexts, or in cases where it's not possible to know in advance whether a module will be used on the main thread or in a worker.


这是否意味着模块加载也会缓存已解析的代码,这意味着如果我们在顶部使用 import 语句将其包含在主线程和工作线程中的模块将不会被再次解析?
然而,这不会发生,每当我们在任何领域(主线程、工作线程)上导入模块时,它们都会独立执行它们的导入,然后以后它们会在自己的领域中引用其解析缓存的实例。
我真的很困惑,作者到底想解释什么。以及我们如何实现它。
相关文章:https://developers.google.com/web/updates/2017/12/modulepreload#does_preloading_modules_help_performance

最佳答案

我不确定这篇文章是从哪里得到这个想法的,但是阅读规范,我没有看到任何证据表明

Preloaded modules can also be used by both the main thread and module workers.



如果我们检查规范,fetch and process the linked resource algorithm for modulepreload links算法在第 5 步执行
  1. Let settings object be the link element's node document's relevant settings object.

然后在第 11 步将此设置对象传递给 fetch a modulepreload module script graph算法,它本身会调用 fetch a single module scriptfetch the descendants of and link — 最终也将调用 fetch 单个模块脚本 — 具有相同的设置对象。
这个settings objectmodule map将被找到,并且此模块映射将用于 fetch a single module script避免多次请求同一个模块(缓存)。
  1. Let moduleMap be module map settings object's module map.

  2. If moduleMap[url] is "fetching", wait in parallel until that entry's value changes, then queue a task on the networking task source to proceed with running the following steps.

  3. If moduleMap[url] exists, asynchronously complete this algorithm with moduleMap[url], and return.


应该注意的是,虽然这个算法 creates a module script ,它还没有执行它。

所以从那里我们可以看到 modulepreload链接不仅会获取链接的资源,还会获取所有子资源,甚至为这些资源中的每一个准备模块脚本,这与本文所声称的内容非常吻合。
但是,这还不足以得出关于有问题的报价的任何结论。
我们必须去查看有关 dedicated Workers constructor 的规范,这将调用 run a worker算法通过一样的我们的modulepreload 文档的对象设置链接正在使用,这次称为“外部设置”。
在此 run a worker 的第 8 步算法,它要求
  1. Set up a worker environment settings object with realm execution context and outside settings, and let inside settings be the result.

还有这个set up a worker environment settings object算法将仅使用文档的外部设置来设置 inherited origin内部值和新设置对象的 top-level origin属性(property)。
这个新设置对象的模块映射是the one of its global scope ,它“最初是空的”。
工作人员的环境设置对象不会从外部设置继承其模块映射。
所以当 worker 自己会调用这些 fetch a single module scriptfetch the descendants of and link作为 fetch a module worker script graph 一部分的算法,它将检查的一个模块映射是它自己的内部设置的模块映射,它不会找到我们的模块脚本modulepreload链接已创建。

因此,通过阅读规范,我会说 modulepreload links 对模块 Workers 的唯一帮助是 HTTP 缓存已经下载了图中的所有文件。如果你打算只在 Worker 中使用这些模块,那么让它在文档一侧准备模块脚本实际上会适得其反,而简单的 prefetch链接可能会做得更好,除了您必须为每个子资源创建一个这样的链接。

关于javascript - 当脚本加载为 "preload"/"modulepreload"时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63761046/

相关文章:

node.js - 如何在 WebWorkers 中浏览器化独立模块

javascript - Promise.race 在第一次履行后是否会拒绝其他 promise ?

javascript - 我如何从异步存储中检索数据并在我的组件中使用它?

javascript 在点击时添加事件类

javascript - Web Worker 的无文档 Canvas

javascript - 通过 webworker 创建通知

javascript - 未捕获的 TypeError : (0 , _module) 不是一个函数

javascript - 如何在 TypeScript 中导入 Vanilla JS ES6 模块?

javascript - Chrome 62 JavaScript 模块

javascript - Iphone 在点击时使 div 变暗