这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战
上一篇文章我们使用了浏览器的 worker
方法,今天我们在来尝试用另外一种方法来获取文件的 hash
这个方法得益于 React
的 Fiber
, 关于 Fiber
的原理我们在这里先不做过多的说明,就是把一个耗时比较长的任务切分成小片,每一个小片完成之后把任务之后就交还给 React
控制权,没其他优先级高的任务,就继续执行切分小片的任务。
关于 React Filber
,我们在说明一点,它有用到 requestIdleCallback
这个方法,显而易见,根据名字我们就知道它是一个回调函数,就是在浏览器空闲时间可以使用的一个方法,但是它的兼容性不太好,還是一个实验性的功能。
关于 requestIdleCallback api 文档点这里
window.requestIdleCallback()方法插入一个函数,这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。
根据这个思想我们也来折腾一下我们的文件上传
- 我们先来定义一个需要执行的函数
- 当切片没有上传完毕且浏览器有空闲时间我们就执行切片任务
- 计算进度条
我们還是先利用 sparkMD5
来产生一个 buffer
的数组,每执行一个小片的任务就通过 appendToSpark
方法放在这个数组里面
const spark = new sparkMD5.ArrayBuffer()
这种方法的进度条可能就没有之前的那么精准了,这里是用 当前完成的小片任务数/切片总数 得到的,每个任务执行的 chunk
越大,进度条的精确度越小
这篇文章主要是开拓一下视野,当我们了解到了一些好的思想(Filber
)看自己去能不能搞点有意思的东西实践一下。
下面附上完整的代码
export const calculateHashIdle = async (chunks: Array<chunksType>, hashProgress: any) => {
return new Promise((resolve) => {
const spark = new sparkMD5.ArrayBuffer()
let count = 0
const appendToSpark = async (file: any) => {
return new Promise((resolve): void => {
const reader = new FileReader()
reader.readAsArrayBuffer(file)
reader.onload = (e) => {
spark.append(e.target.result)
resolve()
}
})
}
const workLoop = async (deadline) => {
// timeRemaining 获取当前帧的剩余时间
while (count < chunks.length && deadline.timeRemaining() > 1) {
// 空闲时间,且有任务
await appendToSpark(chunks[count].file)
count++
if (count < chunks.length) {
// 进度条
hashProgress.value = Number(((100 * count) / chunks.length).toFixed(2))
} else {
// 小片任务执行完毕进度条设置为 100
hashProgress.value = 100
resolve(spark.end())
}
}
window.requestIdleCallback(workLoop)
}
window.requestIdleCallback(workLoop)
})
}
复制代码
补充说明:
deadline
有两个参数
- timeRemaining(): 当前帧还剩下多少时间
- didTimeout: 是否超时
requestIdleCallback
的缺陷
requestIdleCallback is called only 20 times per second - Chrome on my 6x2 core Linux machine, it's not really useful for UI work。—— from Releasing Suspense
这段话的意思是 requestIdleCallback 的 FPS 只有 20, 而页面的 fps 是 60(即一帧为 16.7 s),这远远低于页面流畅度的要求!