如何将FileReader base64捕获为变量? [英] How to capture FileReader base64 as variable?

查看:151
本文介绍了如何将FileReader base64捕获为变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我希望能够将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);

它当前没有打印任何内容到控制台.

问题:

如何将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

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

解决方案

,它是封装异步计算的对象:

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 /等待:

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

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

This prints base64 out to console:

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

Source: https://stackoverflow.com/a/36281449/1063287

jsFiddle: jsFiddle demo of the above working code

I want to be able to assign the base64 to a variable, so I tried the following, based on 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);

It is currently printing nothing out to the console.

Question:

How can I save the base64 value as a variable?

Edit:

As requested, for context:

I am submitting a form in a Google Apps Script environment.

I have done this previously and passed a form object (which included a file) through to the Google Apps Script function.

However, one of the constraints of this approach is that if passing a form object as a parameter, it is the only parameter allowed.

A form element within the page is also legal as a parameter, but it must be the function’s only parameter

Source

In this instance, I am passing multiple parameters through, and one of the parameters will be a pdf file, converted to base64.

In response to @Aasmund's great answer, I would like the variable assignment to block further code execution:

var my_pdf_file = [ converted file here ];

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

Otherwise, I will have to refactor the remaining code to take place in the then block (suggested by @Aasmund), and that might be messy / impossible due to the amount of validation / variable preparation / conditional handling that is taking place before the form is submitted.

解决方案

FileReader.readAsDataURL() is asynchronous - the download happens in the background while the rest of the code keeps executing. So the reason console.log(my_pdf_file_as_base64); prints an empty string is that the line my_pdf_file_as_base64 = e.target.result hasn't been executed yet: the call to getBase64() finishes almost immediately, and the subsequent statement is executed; only later (when the download is complete) will the callback be executed.

The way to handle this is to place the code that uses the downloaded file inside the callback:

getBase64(my_pdf_file, function(e) {
    my_pdf_file_as_base64 = e.target.result;
    console.log(my_pdf_file_as_base64);
});

Alternatively, you can repeatedly (e.g. inside a setTimeout callback or inside some DOM event handler) check if reader.readyState === FileReader.DONE - whenever this becomes true, reader.result will contain the file.

A more flexible approach is to use a Promise, which is an object that encapsulates an asynchronous computation:

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

So far, this looks pretty similar to the first solution, but the advantage is that promise is an object that you can pass around to other functions, so that you can start a computation in one place and decide in another place what should happen when it's finished.

As you have probably noticed, neither of these approaches allow you to block further code execution until the file content has been assigned to the global variable my_pdf_file_as_base64. This is by design; however, if you really really need to block on the download because you don't have time to refactor old code, see the discussion in https://stackoverflow.com/a/39914235/626853. If your user's browsers are sufficiently modern, you can use async/await:

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

(Note that await only works inside async functions, so your click handler must be async. I also experimented with adding a busy waiting loop, but that caused my browser to hang.)

这篇关于如何将FileReader base64捕获为变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆