【问题标题】:How to capture FileReader base64 as variable?如何将 FileReader base64 捕获为变量?
【发布时间】:2018-04-22 01:11:55
【问题描述】:

这会将 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

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

jsFiddle: jsFiddle demo of the above working code

我希望能够将base64分配给一个变量,所以我尝试了以下,基于this answer

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);

它目前没有向控制台打印任何内容。

问题:

如何将 base64 值保存为变量?

编辑:

根据要求,针对上下文:

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

我之前已经这样做了,并将一个表单对象(包括一个文件)传递给 Google Apps 脚本函数。

但是,这种方法的一个限制是,如果将表单对象作为参数传递,它是唯一允许的参数。

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

Source

在这种情况下,我传递了多个参数,其中一个参数将是一个转换为 base64 的 pdf 文件。

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

var my_pdf_file = [ converted file here ];

// don't do this stuff until the above variable is assigned

否则,我将不得不重构剩余代码以在 then 块中进行(@Aasmund 建议),由于验证/变量准备/条件处理的数量,这可能是混乱/不可能的在提交表格之前进行。

【问题讨论】:

    标签: javascript base64 filereader


    【解决方案1】:

    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);
    });
    

    或者,您可以重复(例如,在 setTimeout 回调中或在某些 DOM 事件处理程序中)检查 reader.readyState === FileReader.DONE 是否为真,reader.result 将包含该文件。

    更灵活的方法是使用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);
    });
    

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

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

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

    (请注意,await 只能在 async 函数中使用,因此您的点击处理程序必须是 async。我还尝试添加一个繁忙的等待循环,但这会导致我的浏览器挂起。)

    (另请注意,来自 Charles Owen 在评论中,readAsDataURL 实际上返回一个 data: URL,因此如果您只想获取 Base64 数据,则需要根据链接文档去除前缀。)

    【讨论】:

    • 根据要求,已在原帖中添加上下文,谢谢。
    • 点击处理程序只是在演示中显示以提示示例行为,实际实例发生在表单验证库的成功处理程序中,我假设它不是异步的。已接受答案,因为它得到了很好的解释和帮助,但是如果将来有人在可以同步分配 FileReader base64 时看到帖子,请告诉我们!谢谢!
    • @AasmundEldhuset 我将如何使用 setTimeout() 执行此方法,您能否提供一个示例,因为我现在对使用 Promise 没有任何乐趣:(
    • @Zabs:我自己实际上并没有尝试过这种方法,但我很确定它应该在reader.readAsDataURL(file); 之后执行var timeoutID = window.setTimeout(function() { if (reader.readyState === FileReader.DONE) { console.log(reader.result); window.clearTimeout(timeoutID); } else { console.log("Downoading..."); } }, 1000);。 (抱歉格式化;代码块似乎在 cmets 中不起作用。)
    • 我真的很喜欢这个 Promise 示例,并且同意这是处理这个问题的一种优雅方式。我要补充一点,返回的结果不仅仅是图像的 base64,它实际上是您用于图像 src 的整个链接。
    【解决方案2】:

    我按照本准则工作

       async function checkFileBase64(el) {
            let inputEl = $(el).find('input[type=file]');
            let promise = getBase64(inputEl[0]);
            return await promise;
        }
        function getBase64(file) {
           return new Promise(function (resolve, reject) {
                let reader = new FileReader();
                reader.onload = function () { resolve(reader.result); };
                reader.onerror = reject;
                reader.readAsDataURL(file.files[0]);
            });
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-22
      • 1970-01-01
      • 1970-01-01
      • 2019-12-25
      • 1970-01-01
      • 2013-07-16
      • 2010-09-15
      • 2018-11-01
      相关资源
      最近更新 更多