创建多个 HTMLAudioElement DOM 元素时,有什么方法可以不冻结 UI
Is there any way to not freeze up the UI when creating multiple HTMLAudioElement DOM elements
标题的问题很好self-explanatory。我有这个网站,允许用户一次上传多个文件。然后它将遍历并检索每个的持续时间。
getDuration(file) {
return new Promise(resolve => {
let reader = new FileReader();
reader.onload = e => {
let audio = new Audio();
audio.onloadeddata = () => {
this.duration = audio.duration;
resolve();
};
audio.src = e.target.result;
};
reader.readAsDataURL(file);
});
}
但是,至少在 Chrome 中,这会在 UI 进行所有处理时非常糟糕地冻结它。无论如何我可以避免这种情况或以不同的方式解决这个问题吗?
您已经可以从不使用 FileReader
和 data:// URIs
开始
FileReader 会将所有文件从磁盘读取到内存中,有很多文件,这是很多 IO,您的磁盘(HDD 或 SSD)不会喜欢它。
然后从该文件创建 data:// URL 不是免费操作,因此需要一些 CPU 时间。
最后,浏览器必须将该数据 URL 解码回原始二进制文件,然后才能尝试将该数据解码为音频。这里又是一些不必要的步骤,浪费了很多内存。
相反,您可以简单地从您的用户发送的文件中创建一个 blob:// URL,并将您的 <audio>
的 src 设置为此。这将是一个指向磁盘上实际文件的简单指针,因此浏览器将能够流解码它并仅在内存中附加它需要的数据块。
要创建这样的 blob:// URL,您必须使用 URL.createObejctURL()
方法。
请注意,即使对于来自磁盘的文件,它 并不重要,您应该养成良好的习惯,在使用后撤销此类 blob:// URLs它,因为它们会阻止文件被垃圾收集。
function getDuration(file) {
return new Promise(resolve => {
const audio = new Audio();
audio.onloadedmetadata = () => {
URL.revokeObjectURL(file)
resolve(audio.duration);
};
audio.src = URL.createObjectURL(file);
});
}
document.querySelector("input").oninput = async (evt) => {
console.log( await getDuration( evt.target.files[0] ) );
}
<input type="file">
标题的问题很好self-explanatory。我有这个网站,允许用户一次上传多个文件。然后它将遍历并检索每个的持续时间。
getDuration(file) {
return new Promise(resolve => {
let reader = new FileReader();
reader.onload = e => {
let audio = new Audio();
audio.onloadeddata = () => {
this.duration = audio.duration;
resolve();
};
audio.src = e.target.result;
};
reader.readAsDataURL(file);
});
}
但是,至少在 Chrome 中,这会在 UI 进行所有处理时非常糟糕地冻结它。无论如何我可以避免这种情况或以不同的方式解决这个问题吗?
您已经可以从不使用 FileReader
和 data:// URIs
FileReader 会将所有文件从磁盘读取到内存中,有很多文件,这是很多 IO,您的磁盘(HDD 或 SSD)不会喜欢它。
然后从该文件创建 data:// URL 不是免费操作,因此需要一些 CPU 时间。
最后,浏览器必须将该数据 URL 解码回原始二进制文件,然后才能尝试将该数据解码为音频。这里又是一些不必要的步骤,浪费了很多内存。
相反,您可以简单地从您的用户发送的文件中创建一个 blob:// URL,并将您的 <audio>
的 src 设置为此。这将是一个指向磁盘上实际文件的简单指针,因此浏览器将能够流解码它并仅在内存中附加它需要的数据块。
要创建这样的 blob:// URL,您必须使用 URL.createObejctURL()
方法。
请注意,即使对于来自磁盘的文件,它 并不重要,您应该养成良好的习惯,在使用后撤销此类 blob:// URLs它,因为它们会阻止文件被垃圾收集。
function getDuration(file) {
return new Promise(resolve => {
const audio = new Audio();
audio.onloadedmetadata = () => {
URL.revokeObjectURL(file)
resolve(audio.duration);
};
audio.src = URL.createObjectURL(file);
});
}
document.querySelector("input").oninput = async (evt) => {
console.log( await getDuration( evt.target.files[0] ) );
}
<input type="file">