0

I want to access file content outside the "onload" function. I know this has something to do with asynchronous. Here is my js function:

function testZ() {
var entireFile = document.getElementById("input").files[0];
var reader = new FileReader();
reader.readAsText(entireFile, "UTF-8");
reader.onload = function (e) {
    var rawLog = reader.result;
    console.log(rawLog);
};

// access to file content

Thank you!

tomc
  • 1
  • is it possible to declare a variable (say `let fileDataRaw;`) outside the function. And then, before the `console.log(rawLog)`, you could try: `fileDataRaw = rawLog;` to assign the value? Finally, you are able to access the data (ie, file-content) outside the `onload`. Please note that before the result is populated, the variable may be undefined. – jsN00b Oct 06 '22 at 08:08
  • https://stackoverflow.com/a/49498359/9947071 – Philip F. Oct 06 '22 at 08:09
  • @jsN00b - no, because asynchrony – Jaromanda X Oct 06 '22 at 08:14
  • Since you're reading that File as UTF-8 you can simply do `const text = await file.text()`. If you needed to read it using another encoding, you could have done `const text = (new TextDecoder(encoding)).decode(await file.arrayBuffer())`. – Kaiido Oct 11 '22 at 05:41

1 Answers1

0

Traditionally, you can use a callback pattern like so

function testZ(cb) {
    var entireFile = document.getElementById("input").files[0];
    var reader = new FileReader();
    reader.readAsText(entireFile, "UTF-8");
    reader.onload = function (e) {
        var rawLog = reader.result;
        cb(rawLog);
    };
}

testZ(contents => {
    // contents accessible here
})

Alternatively, you can make the code look more like synchronous code using Promises and async/await

function testZ() {
    return new Promise((resolve, reject) => {
        var entireFile = document.getElementById("input").files[0];
        var reader = new FileReader();
        reader.readAsText(entireFile, "UTF-8");
        reader.onload = () => resolve(reader.result);
        reader.onerror = reject;
    });
};
(async() => {
    const contents = await testZ();
    // contents accessible here
})();

Note: the asynchronous IIFE would not be required if you are in a function, just make that function async - with the usual caveats that the function now returns a Promise, so don't expect syncrhonous results from it

async someFunction() {
    const fileContent = await testZ();
    // contents accessible here
}

Also, top-level await is available in modules - so, no need to have an async function at all in this case - simply:

const fileContent = await testZ();
// contents accessible here
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Thanks!!! I choose to use Promises. I now have issues with functions like contents.match which always return null – tomc Oct 06 '22 at 09:50
  • you probably didn't heed my warning and calling `testZ` expecting synchronous results - or expect the function calling `testZ` to return synchronous results ... asynchrony is a *virus*, once you use it, everything that uses it needs to be coded with asynchrony in mind – Jaromanda X Oct 06 '22 at 09:53