比如页面上有一个 <input type="file" onChange="todo">
的选择器,我选择完以后绑定相对应的 onChange
事件。
function todo(){}
const fileReader = new FileReader()
const file=inputElement.files[0]
//接下来处理文件
//fileReader 的一些文件处理方法
if (file) {
fileReader.readAsDataURL(file)
}
fileReader.addEventListener(
'load',
() => {
const result = fileReader.result
const resultContainer = document.getElementById('result')
const img = document.createElement('img')
img.src = result
resultContainer.append(img)
},
{ once: true }
)
这种 FilerReader
实例化以后再进行读取操作的方法我在学习 go
这门语言中也见到过类似的设计。
问题:我好奇的点在于,为什么我们总要创建一个 fileReader
事例再去做一些事情?(为什么不直接给构造函数传参数 fileReader= new FileReader([file])
然后假设就可以在 fileReader
实例的属性上进行读取操作。比如:fileReader.result
、fileReader.readAsDataUrl
)
这种设计模式有什么好处吗?或者说 new FileReader(file)
直接传参有什么弊端吗?
为什么要实例化
FileReader
再用?实例化再用,更容易扩展逻辑。
比如你的例子,
如果后续有人反馈,文件很大,读取文件需要很长时间,希望加进度条,有了
FileReader
实例,我们就能方便地再加一个监听函数如果后续又有人提出增加可以取消按钮,我们可以继续利用
FileReader
实例,调用abort()
方法中断读取。由上可见,实例化
FileReader
再操作,可以更灵活地利用FileReader
提供的接口,做更多的事。然后再说说为什么不是直接
new FileReader(file)
。如果做过
java
开发,会发现java
确实是这么干的。以下是我的推测了,不一定正确。
首先
JS
天生是异步的,文件的加载异步过程,一般不会设计在构造函数里。你肯定不会见过、也不允许写出这样的构造函数:当然,你也可以说,构造函数里并不立刻加载文件,可以在调用
fileReader.readAsDataUrl()
再加载嘛。这样的设计确实可行。但这需要考虑一点,就是避免不必要的理解成本。
new FileReader(file)
再fileReader.readAsDataUrl()
,会给人造成错误的理解,误认为文件加载发生在构造函数中。如果换成new FileReader()
再fileReader.readAsDataUrl(file)
,那就能明确提示文件加载是发生在后一步里。另外先
new FileReader()
再fileReader.readAsDataUrl(file)
还有一点好处,就是可以单例复用,比如:这样可以减少
FileReader
的构造次数。另外再提一下,
FileReader
和XMLHttpRequest
差不多是一个年代的产物,那时候非常推崇OOP
(面向对象),所以“先实例化再调用方法”这种API设计也很流行。比如XMLHttpRequest
:是不是感觉跟
FileReader
有几分相像?不过现在有了
fetch
,就不需要那么麻烦了。你可能会好奇
FileReader
有没有替代的方案?有,但要具体分析,取决于你要获取怎样的数据。
还是以
<input type="file" id="input">
为例。如果是加载文本:
如果是加载图片: