💰 点进来就是赚到知识点!本文带你用 JS 代码监控本地文件,点赞、收藏、评论更能促进消化吸收!
🚀 想解锁更多 Web 文件系统的技能吗?快来订阅专栏「Web 玩转文件操作」!
📣 我是 Jax,在畅游 Web 技术海洋的又一年,我仍然是坚定不移的 JavaScript 迷弟,Web 技术带给我太多乐趣。如果你也和我一样,欢迎关注、私聊!
开门见 demo
先来玩玩这个 demo —— 在 Chrome 中监控本地文件夹。
在上面的 demo 中,点击按钮选择一个本地文件夹后,无论是在该文件夹中新增、修改还是删除内容,网页端都能够感知到每一步操作的细节,包括操作时间、操作对象是文件还是文件夹、具体执行了什么操作等等。
如果你的感觉是:”哟?有点儿意思!“ 那么这篇文章就是专门为你而写的,读下去吧。
在本专栏的前几篇文章中,我们已经知道,Web 应用能对本地文件进行各种花式操作,例如选择文件/文件夹、增/删/改/查文件等等。网页好像能伸出长长的手臂,穿过浏览器触摸到了用户的本地文件。但你可能还不知道,网页也能长出千里眼、顺风耳,本地文件有什么风吹草动,都能被网页端监控到。如此灵通的耳目,它的名字就是 File System Observer API(文件系统观察者)。
API 简介
现在想象我们要开发一个 Web 端相册应用,展示用户本地文件夹中的图片。我们希望这个相册能实时响应用户的操作,例如增加/删掉几张图片后,无需用户手动在 Web 端刷新,就能自动更新到最新状态。
如果请你来实现自动刷新,阁下又该如何应对?
经典思路可能会是以短时间间隔轮询文件夹状态,读取并缓存每个文件的 lastModified
时间戳,如果前后两次轮询的时间戳发生了变化,再把前后差异更新到 Web 视图中。这种实现方式能达到效果,但还是有一些缺点,比如不能真正做到即时响应,且会有很大的性能问题等。
其实咱们都知道,最优雅高效的做法是仅在文件被操作时触发更新。原生操作系统如 WIndows 和 MacOS 都有这样的文件监听机制,但显然目前 Web 端还无法享受其便利性。除了在用户端,Node.js 应用也面临这样的问题。开发者苦此久矣。
直到 2023 年 6 月,来自谷歌的贡献者们开始推进一项 W3C 提案 —— File System Observer(为方便叙述,下文将简称其为 FSO),旨在从浏览器层面向 Web 应用提供跨平台的文件监听支持。如果这项提案能够顺利进入 ECMAScript 标准,那么 Web 文件系统的又一块重要功能版图将得以补全,Web 生态将会变得更友好、更强大。
解锁尝鲜:加入 Origin Trial
FSO 还是一套崭新的 API,有多新呢?MDN 和 CanIUse 中还没有建立关于它的词条。但这并不意味着我们完全无法用于生产环境 —— 正如你在本文开头的 demo 中体验到的,我已经用到线上功能中了。只要做一点配置工作,你和你的用户就能成为全球第一批享受到 FSO 的人 😎。
Chrome 已经对 FSO 开启了试用,版本范围是 129 到 134,你可以为你的 Web App 域名注册一个试用 token,你可以跟着我一步一步操作:
首先我们访问 developer.chrome.com/origintrial… 并登录账号。
点击界面下方的「REGISTER」按钮,进入表单页:
按照上图的标注填写信息。每一个域名都需要单独注册一次。例如我本地开发调试时用的是localhost:3000,而线上域名是 rejax.fun,那么就需要给这两个域名分别走一遍 REGISTER 流程。
填写信息后提交表单,你会得到一串字符串 token:
将 token 复制出来,写到 Web App 的 html 文件中,像这样:
<meta http-equiv="origin-trial" content="把 token 粘贴到这里" />
或者用 JavaScript 动态插入:
const meta = document.createElement('meta')
meta.httpEquiv = 'origin-trial'
meta.content = token
document.head.appendChild(meta)
最后,在 Chrome 中打开你注册的域名所在的页面,在 Console 中输入 FileSystemObserver
并回车:
如果打印出了「native code」而不是「undefined」,那么恭喜,你已经成功解锁了 FSO 试用!
监听一个文件
有了试用资格,我们来监听一个文件,边调试代码边研究 FSO 的设计和实现。
实例化
上一小节的最后,我们用来测试是否解锁成功的 FileSystemObserver
就是 FSO 的构造函数,它接收一个回调函数作为参数。我们可以像这样实例化一个观察者:
function callback (params) {
console.log(params)
}
const observer = new FileSystemObserver(callback)
callback
函数会在被监听的文件发生变动时被执行,所以我们可以把响应变动的业务处理逻辑放在其中。
绑定目标文件
实例 observer
有一个 observe
方法,它接收两个参数。第二个参数暂且按下不表,我们先专心看第一个参数。
这个参数是一个 FileSystemHandle
格式的对象,代表着本地文件在 JavaScript 运行时中的入口。我们可以通过 showOpenFilePicker
来选择一个文件(假如我们选择了文件 a.js
),并获取到对应的 FileSystemHandle
。
const [fileHandle] = await window.showOpenFilePicker()
observer.observe(fileHandle)
如果你想看
FileSystemHandle
和showOpenFilePicker
的详解,可以移步至本专栏的上一篇文章《谁也别拦我们,网页里直接增删改查本地文件! 》。
调用 observe
方法后,这个文件就算是进入了我们的监控区域 📸 了,直到我们主动解除监听或者网页被关闭/刷新。
监听文件操作
当我们编辑文件 a.js
的内容时,给 observe()
传入的回调函数被调用,并且会接收到两个参数,第一个是本次的变动记录 records
,第二个是实例 observer
本身。我们打印 records
可以看到如下结构:
records
是一个数组,其元素是 FileSystemChangeRecord
类型的对象,我们重点关注以下几个属性:
一般情况下,如果我们监听的是单个文件而不是一个目录,那么无论是把文件移走、重命名、删除, record
中的 type
值都会是 disappeared。
监听一个文件夹
监听文件夹的方式和监听文件类似,我们先用 showDirectoryPicker
选择一个文件夹(以文件夹 foo
为例),再把 DirectoryHandle
传入 observe
方法。
为方便描述,我们假设文件夹 foo 的结构如下:
/foo
├── 文件夹 dir1
├── 文件夹 **dir2**
└── 文件 a.js
const dirHandle = await window.showDirectoryPicker()
observer.observe(dirHandle)
与文件有所不同的是,文件夹会有子文件夹和子文件,这是一个树形结构。如果我们只想监听 foo
下面的一级子内容,那么使用像上方代码块那样的调用方式就可以了。但如果我们想密切掌控每一子级的变动,就需要额外的配置参数,也就是前文提到的第二个参数:
observer.observe(dirHandle, {
recursive: true
})
此时你可以在 foo 文件夹里面任意增、删、改子文件或文件夹,一切操作都能在回调函数里以 record
的形式被捕获到。子文件和子文件夹所支持的操作类型,record
值也具有相同结构,因此接下来我们从监听子文件的视角来观察 FSO。
监听子文件
创建和移入、删除和移出 a.js
的情况,record.type
的值分布如下:
文件移入 foo | 在 foo 中创建文件 | 文件从 foo 中移出 | 删除文件 |
---|---|---|---|
appeared | appeared | disappeared | disappeared |
其中移出和删除的表现,与监听单文件的情况是相同的。
我们来试试把 a.js
移到与它同级的文件夹 dir1
中,看看会得到怎样的 record
。
有几个点值得我们注意:
type
的值是 moved,说明只要a.js
还在foo
内,不管处于第几层,都不会触发type: appeared/disappeared
relativePathMovedFrom
是一个单元素数组,它代表移动前a.js
的文件路径relativePathComponents
有两个数组元素,代表被移动文件的新路径是dir1/a.js
但重命名子文件和监听单文件时不同。例如我们将 a.js
更名为 b.js
,会监听到如下 record
:
我们本以为 type
的值是 renamed,但其实是 moved,确实有点反直觉。从 record 上来看,与真正的移动操作相比,重命名的不同之处在于:
changedHandle
指向了重命名后的新文件b.js
relativePathMovedFrom
和relativePathComponents
分别包含的是旧名和新名
FSO 在状态设计上并没有直接定义一个重命名状态,但我们可以自己来区分。重命名的响应数据有这样的特征:
relativePathMovedFrom
和relativePathComponents
这两个数组的 length 一定相等- 且除了最后一个元素,两个数组的其他元素一定是一一对应相等的
因此我们可以这样判断重命名操作:
const { oldList: relativePathMovedFrom, newList: relativePathComponents } = recors[0]
let operation = '是常规的移动操作'
if (oldList.length === newList.length) {
const len = newList.length
for (let i = 0; i < len; i++) {
const isEqual = newList[i] === oldList[i]
if (i < len - 1) {
if (!isEqual) break
} else if (!isEqual) {
operation = '是重命名操作,不是移动操作'
}
}
}
至此,我们已经摸清了如何监听子文件上的不同操作,除了监听单文件部分已经覆盖到的内容,增量知识点仅有移动和重命名这两块。
监听子文件夹
对子文件夹的操作,也不外乎新建、删除、移动、重命名,和子文件在逻辑上基本一致,我们可以直接复用子文件的监听逻辑,再加上用 record.changedHandle.kind === ‘directory’
来判断是否是文件夹即可。
解除监听
当我们想主动解除对文件或文件夹的监听时,只需要调用对应 observer
的 disconnect
即可:
observer.disconnect()
结语
恭喜你读完了本文,你真棒!
这一次,我们勇敢地品尝了一只新鲜生猛的螃蟹,对 File System Observer API 进行了较为深入的理解和实践。如果你之前一直苦于 JS 无法监听文件,无法带给用户完备的功能和极致的体验,那么从现在开始,你可以开始着手准备升级你的 Web App 了!
这套船新版本的 API 有力地补齐了 Web 文件系统 API 的短板,增强了 Web App 的实现能力,提升了开发者和用户的体验。它还在不断修改完善中,非常需要我们开发者积极参与到标准的制定中来,让 Web 技术栈变得更高效、更易用!
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=21230,转载请注明出处。
评论0