在Javascript中同步读取文件

Lai*_*ila 38 javascript html5 filereader

我想读取一个文件,并使用FileReader对象将其转换为base64编码的字符串.这是我使用的代码:


    var reader = new FileReader();
    reader.onloadend = function(evt) {  
        // file is loaded
        result_base64 = evt.target.result; 
    };
    reader.readAsDataURL(file); 


但在这种情况下,我在事件处理程序(onLoadEnd事件)中获得转换的结果.我想要一个同步方法.有没有办法"readAsDataURL"方法可以直接返回'result_base64'变量的值?

谢谢

Joh*_*isz 26

您可以使用标准FileReaderSync,它是 FileReader API 的更简单、同步、阻塞版本,类似于您已经在使用的:

let reader = new FileReaderSync();
let result_base64 = reader.readAsDataURL(file); 

console.log(result_base64); // aGV5IHRoZXJl...
Run Code Online (Sandbox Code Playgroud)

请记住,由于显而易见的原因,这仅在工作线程中可用


如果您需要一个“读起来像”同步 API 的主线程解决方案,即按顺序,您可以将异步 FileReader 包装在承诺中并使用异步函数(您可能需要转译):

async function readFileAsDataURL(file) {
    let result_base64 = await new Promise((resolve) => {
        let fileReader = new FileReader();
        fileReader.onload = (e) => resolve(fileReader.result);
        fileReader.readAsDataURL(file);
    });

    console.log(result_base64); // aGV5IHRoZXJl...

    return result_base64;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在另一个异步上下文中等待这个函数:

async function main() {
    let file = new File(...)
    let dataURL = await readFileAsDataURL(file)
    console.log(dataURL); // aGV5IHRoZXJl...
}
Run Code Online (Sandbox Code Playgroud)

...或者只是使用承诺回调来使用它(不需要异步上下文):

readFileAsDataURL(file).then(dataURL => {
    console.log(dataURL); // aGV5IHRoZXJl...
});
Run Code Online (Sandbox Code Playgroud)

  • 是的,也许值得注意,如果你从其他函数调用它,它也应该是异步的,并使用 `await` 关键字调用它,否则它只会返回“promise 对象”。 (2认同)
  • “FileReaderSync”在哪里定义?我收到错误 (2认同)
  • @sgowd 你尝试过网络工作者吗?它不会在主线程上工作。 (2认同)

Dav*_*iña 16

同步任务(阻塞)通常很糟糕.如果没有真正的理由异步执行此操作,我强烈建议您使用事件回调.

想象一下你的文件坏了,HTML5读了很多,它不会给你结果.它会破坏您的代码并阻止该网站.或者,有人可以选择一个10GB的文件,这会冻结您的HTML页面,直到文件完全加载.使用该异步事件处理程序,您可以捕获可能的错误.

要解决回调的限制,我使用一个简单的技巧:

var ready = false;
var result = '';

var check = function() {
    if (ready === true) {
         // do what you want with the result variable
         return;
    }
    setTimeout(check, 1000);
}

check();

var reader = new FileReader();
reader.onloadend = function(evt) {
    // file is loaded
    result = evt.target.result;

    ready = true;
};
reader.readAsDataURL(file);
Run Code Online (Sandbox Code Playgroud)

check函数,每秒检查ready标志变量是否设置为true.如果是这样,您可以确定结果可用.

这可能不是最好的做法,但我使用这种技术制作了一个webapp大约30次,同时运行超过10个setTimeout,直到现在都没有遇到任何问题.

  • 当然你是对的,但由于这个问题是关于 javascripts html5 filereader 我们可以安全地假设我们正在谈论浏览器环境。 (3认同)
  • 这不是同步任务。 (3认同)
  • /sf/answers/3278304991/ 这种方法很好,但它仍然异步工作。 (2认同)
  • “同步任务(阻止)通常很糟糕”-错误。尽管对于常见的特定环境(例如与Web开发相关的环境)是正确的,但它通常不是坏的。(例如,嵌入式硬件上的单线程非Web非UI专用应用程序) (2认同)