tl;dr资源预加载为
<link rel="preload" href="..." as="fetch" crossorigin="anonymous">
似乎不会被Web Worker中发生的fetch
调用使用。
为什么会这样?我是否需要对预加载标签进行更改,或者采取其他解决方法?
上下文:我有一个Web Worker,它下载并处理大量CSV数据。处理相当密集,所以我想把它放在主线程之外。
然而,我希望有一种方法可以更早地启动下载,这样工作人员就可以在工作人员启动后更快地开始处理它。
我尝试为资源添加一个<link rel="preload" as="fetch" ...>
,这对于从main线程获取非常有效——但如果我从工作线程获取相同的资源,如果预加载的资源未使用(启动了一个单独的请求,我可以看到控制台上打印的标准"资源已使用链接预加载进行预加载,但在窗口加载事件后的几秒钟内未使用"警告)。
事实上,尽管Workers确实拥有与其所有者Document
相同的(克隆)策略容器,但仅此而已,并且预加载资源的映射是不共享的。
因此,对于您的情况,您可以使用<link>
、fetch()
在主线程中预加载,将Response
作为ArrayBuffer
(这是最原始的格式)使用,并将ArrayBuffer
传输到Worker
:
<link rel="preload" href="..." as="fetch" crossorigin="anonymous">
// ...
const resp = await fetch("...");
if (!resp.ok) { handleNetworkError(resp) }
const buffer = await resp.arrayBuffer();
const worker = new Worker(/*...*/);
worker.postMessage({ buffer }, [buffer]);
在你的Worker
中,你会做
onmessage = ({ data }) => {
if (data.buffer) {
const csvText = new TextDecoder().decode(data.buffer);
parseCSV(csvText);
}
};
这样做,您仍然可以利用预加载,并且对主线程的影响仍然非常小:获取是并行进行的,将Response
作为ArrayBuffer
消耗掉不需要任何计算,也不应该将数据传输到Worker
。但这比直接从Worker
中获取要复杂一些。
根据您的情况,另一个解决方案可能是使用ServiceWorker
预取资源并缓存它们。然后,您的Worker
就可以点击缓存了。