如何捕获FileReader base64作为变量?

use*_*287 8 javascript base64 filereader

这将base64输出到控制台:

function getBase64(file) {
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function() {
        console.log(reader.result);
    };
    reader.onerror = function(error) {
        console.log('Error: ', error);
    };
}

var file = document.querySelector('#files > input[type="file"]').files[0];
getBase64(file); // prints the base64 string
Run Code Online (Sandbox Code Playgroud)

资料来源: https ://stackoverflow.com/a/36281449/1063287

jsFiddle: 上面工作代码的jsFiddle演示

我希望能够将base64分配给变量,所以我根据这个答案尝试了以下内容:

function getBase64(file, onLoadCallback) {
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = onLoadCallback;
    reader.onerror = function(error) {
        console.log('Error when converting PDF file to base64: ', error);
    };
}

var my_pdf_file = document.querySelector("#my_pdf_file").files[0];
var my_pdf_file_as_base64 = "";
getBase64(my_pdf_file, function(e) {
    my_pdf_file_as_base64 = e.target.result
});

// print out the base64 to show i have captured the value correctly
console.log(my_pdf_file_as_base64);
Run Code Online (Sandbox Code Playgroud)

它目前没有打印到控制台.

题:

如何将base64值保存为变量?

编辑:

根据要求,上下文:

我正在Google Apps脚本环境中提交表单.

我之前已经完成了这项工作,并将表单对象(包含文件)传递给了Google Apps脚本功能.

但是,此方法的一个约束是,如果将表单对象作为参数传递,则它是唯一允许的参数.

页面中的表单元素也是合法的参数,但它必须是函数的唯一参数

资源

在这个例子中,我传递了多个参数,其中一个参数将是一个pdf文件,转换为base64.

为了回应@ Aasmund的好答案,我希望变量赋值可以阻止进一步的代码执行:

var my_pdf_file = [ converted file here ];

// don't do this stuff until the above variable is assigned
Run Code Online (Sandbox Code Playgroud)

否则,我将重构的剩余代码,以发生在then块(由@Aasmund建议的),并且这可能是杂乱的/不可能的,因为正在发生前的形式是验证的量/可变制备/有条件处理提交.

Aas*_*set 18

FileReader.readAsDataURL()异步的 - 下载发生在后台,而其余代码继续执行.因此console.log(my_pdf_file_as_base64);打印空字符串的原因是该行my_pdf_file_as_base64 = e.target.result尚未执行:调用getBase64()几乎立即完成,并执行后续语句; 只有在稍后(下载完成时)才会执行回调.

处理此问题的方法是将使用下载文件的代码放在回调中:

getBase64(my_pdf_file, function(e) {
    my_pdf_file_as_base64 = e.target.result;
    console.log(my_pdf_file_as_base64);
});
Run Code Online (Sandbox Code Playgroud)

或者,您可以重复(例如在setTimeout回调内或某些DOM事件处理程序内)检查reader.readyState === FileReader.DONE- 如果这变为true,reader.result将包含该文件.

更灵活的方法是使用a Promise,它是一个封装异步计算的对象:

function getBase64(file, onLoadCallback) {
    return new Promise(function(resolve, reject) {
        var reader = new FileReader();
        reader.onload = function() { resolve(reader.result); };
        reader.onerror = reject;
        reader.readAsDataURL(file);
    });
}

var promise = getBase64(my_pdf_file);
promise.then(function(result) {
    console.log(result);
});
Run Code Online (Sandbox Code Playgroud)

到目前为止,这看起来与第一个解决方案非常相似,但优点是promise可以传递给其他函数的对象,这样您就可以在一个地方开始计算并在另一个地方决定在它完成时会发生什么.

您可能已经注意到,这些方法都不允许您阻止进一步的代码执行,直到文件内容已分配给全局变量my_pdf_file_as_base64.这是设计的; 但是,如果您确实需要阻止下载,因为您没有时间重构旧代码,请参阅/sf/answers/2793996481/中的讨论.如果您的用户的浏览器足够现代,您可以使用async/await:

$(document).on("click", ".clicker", async function() {
    var promise = getBase64(my_pdf_file);
    var my_pdf_file_as_base64 = await promise;
}
Run Code Online (Sandbox Code Playgroud)

(注意,await只能在async函数内部工作,因此必须使用单击处理程序async.我还尝试添加繁忙的等待循环,但这导致我的浏览器挂起.)