原生支持bgFetch?大文件下载这么玩?

家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

Background Fetch简称bgFetch。

1.为什么是Background Fetch?

深入理解浏览器Background Fetch。 Created by Decipher Zone Softwares

1.1 为什么要Background Fetch?

当 Web 应用程序需要下载大文件时,例如电影、音频文件和软件,通常可能会出现问题,因为用户需要保持与页面的连接才能完成下载。 如失去连接,关闭选项卡等任务将停止。

为什么要Background Fetch?From:istockphoto

Background Synchronization 为 service workers 提供了一种延迟处理直到用户连接的方法。但是不能用于长时间运行的任务,例如下载大文件。 同时,要求 service worker 在完成之前保持活动状态,因为为了节省电池寿命、防止在后台发生不需要的任务,浏览器将在某个时候终止任务。

1.2 Background Fetch解决了什么痛点?

Background Fetch API 解决了这个问题。 它为 Web 开发人员创建了一种方式,让浏览器在后台执行一些操作,例如,当用户单击按钮下载视频文件时。 然后浏览器以用户可见的方式执行提取,显示进度、提供取消下载的方法。 下载完成后,浏览器会打开 Service Worker,此时应用程序可以根据需要对响应执行某些操作。

如果用户在离线时启动进程,后台提取 API 将启用提取。 一旦连接起来,它就会开始。 如果用户下线,该过程将暂停,直到用户再次上线。

2.Background Fetch如何工作?

Background Fetch工作流程如下:

  • 告诉浏览器在后台执行一组fetch。
  • 浏览器调用fetch,向用户显示进度。
  • 一旦获取完成或失败,浏览器就会打开service workers并触发一个事件来告诉你发生了什么,由开发者决定如何处理响应。

如果用户在第 1 步后关闭了站点的页面,下载将继续。

fetch是高度可见的并且很容易中止,所以不存在太长的后台同步任务的隐私问题。 而且service worker 也不会持续运行,所以不用担心滥用系统,例如在后台挖矿。

在某些平台(例如 Android)上,浏览器可能会在第 1 步后关闭,因为浏览器可以将fetch操作交给操作系统。如果用户在离线时开始下载,或者在下载过程中离线,后台fetch将暂停并稍后恢复。

3.浏览器兼容

3.1 特征检测

与任何新功能一样,需要检测浏览器是否支持它。 对于 Background Fetch,可以通过如下代码快速检测:

if ('BackgroundFetchManager' in self) {
  //浏览器支持Background Fetch!
}

从caniuse的数据来看,该API的浏览器整体支持率达到了73.58%。Chrome从74版本开始,Edge从79版本开始都已经支持Background Fetch。不过,可惜的是,FireFox和Safari目前支持并不好。

3.2 实例化Background Fetch

使用 Background Fetch 需要注册一个 service worker。 然后调用 backgroundFetch.fetch() 来执行,同时返回一个Promise。

Background Fetch提取可能会请求多个文件。 在下面的示例中,请求了 MP3 和 JPEG。

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch(
    // service worker的fetch方法
    "my-fetch",
    ["/ep-5.mp3", "ep-5-artwork.jpg"],
    // 请求MP3和JPEG
    {
      title: "Episode 5: Interesting things.",
      icons: [
        {
          sizes: "300x300",
          src: "/ep-5-icon.png",
          type: "image/png",
        },
      ],
      downloadTotal: 60 * 1024 * 1024,
    }
  );
});

3.3 获取已有的Background Fetch


navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

通过传递Background Fetch的id来获取, 如果没有使用该 ID 的Background Fetch,则返回 undefined。

Background Fetch从它被注册的那一刻起就被认为是“活跃的”,直到它成功、失败或被终止。可以使用 getIds 获取所有活动Background Fetch的列表:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

3.4 跟踪Background Fetch进度

可以通过进度事件来完成。请记住,downloadTotal可以是任何值,未提供,则为 0。

bgFetch.addEventListener('progress', () => {
  // If we didn't provide a total, we can't provide a %.
  if (!bgFetch.downloadTotal) return;
  const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
  console.log(`Download progress: ${percent}%`);
});

3.5 获取请求和响应

bgFetch.match('/ep-5.mp3').then(async (record) => {
  if (!record) {
    console.log('No record found');
    return;
  }

  console.log(`Here's the request`, record.request);
  const response = await record.responseReady;
  console.log(`And here's the response`, response);
});

在 Chrome 当前的实现中,您只能在 backgroundfetchsuccess、backgroundfetchfailure 和 backgroundfetchabort service worker 事件期间获取请求和响应(见下文)


4.本文总结

本文主要和大家介绍浏览器的新特性Background Fetch,因为Background Fetch本身的复杂性,文章没有过多的展开。但是文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。


参考资料

https://developer.mozilla.org/en-US/docs/Web/API/Background_Fetch_API

https://caniuse.com/?search=Background%20Fetch

https://developer.chrome.com/blog/background-fetch/

原文链接:,转发请注明来源!