269

I cannot figure out how async/await works. I slightly understand it but I can't make it work.

function loadMonoCounter() {
    fs.readFileSync("monolitic.txt", "binary", async function(err, data) {
       return await new Buffer( data);
  });
}

module.exports.read = function() {
  console.log(loadMonoCounter());
};

I know, I could use readFileSync, but if I do, I know I'll never understand async/await and I'll just bury the issue.

Goal: Call loadMonoCounter() and return the content of a file.

That file is incremented every time incrementMonoCounter() is called (every page load). The file contains the dump of a buffer in binary and is stored on a SSD.

No matter what I do, I get an error or undefined in the console.

Mike
  • 14,010
  • 29
  • 101
  • 161
Jeremy Dicaire
  • 4,615
  • 8
  • 38
  • 62
  • Does this answer your question? [Using filesystem in node.js with async / await](https://stackoverflow.com/questions/40593875/using-filesystem-in-node-js-with-async-await) – KyleMit Nov 18 '19 at 22:20

13 Answers13

459

Since Node v11.0.0 fs promises are available natively without promisify:

const fs = require('fs').promises;
async function loadMonoCounter() {
    const data = await fs.readFile("monolitic.txt", "binary");
    return Buffer.from(data);
}
Marek Sapota
  • 20,103
  • 3
  • 34
  • 47
Joel
  • 15,654
  • 5
  • 37
  • 60
  • 3
    As of 21-Oct-2019, v12 is an active LTS version – cbronson Oct 30 '19 at 03:48
  • 116
    `import { promises as fs } from "fs";` if you want to use import syntax. – tr3online Mar 03 '20 at 17:56
  • 6
    A note on this approach, while it is clean, it also doesn't import other useful features of `fs` outside of the `fs.promises` api. It may be important to import `fs` separately from `fs.promises`. – NonCreature0714 Sep 14 '20 at 06:21
  • I'm getting a weird response with this: Buffer(18524) [60, 115, 99, 114, 105, 112, 116, 32, 116, 110, 116, 45, 108, 105, 98, 62, 13, 10, 32, 32, 32, 32, 47, 42, 42, 13, 10, 32, 32, 32, 32, 32, 42, 32, 67, 111, 112, 121, 114,, …] what could it be? – Paula Fleck Nov 27 '20 at 18:33
  • 4
    Once you have the Buffer, you can convert it to a string using Buffer's method `toString()` like `bufferData.toString()` - see the [docs for Buffer](https://www.w3schools.com/nodejs/met_buffer_tostring.asp). – manosim Dec 18 '20 at 11:45
  • 6
    Hint: call `await fs.readFile("monolitic.txt", "utf8");` to get the file content as a string – Finesse Oct 27 '21 at 04:57
  • I like `const fs = require('fs/promises');` a bit more :) – Velter Nov 09 '21 at 14:02
  • Use `return Buffer.from(data)` or another alternative to avoid (node:76590) [DEP0005] warning. – Tanner Dolby Apr 08 '22 at 20:30
232

To use await/async you need methods that return promises. The core API functions don't do that without wrappers like promisify:

const fs = require('fs');
const util = require('util');

// Convert fs.readFile into Promise version of same    
const readFile = util.promisify(fs.readFile);

function getStuff() {
  return readFile('test');
}

// Can't use `await` outside of an async function so you need to chain
// with then()
getStuff().then(data => {
  console.log(data);
})

As a note, readFileSync does not take a callback, it returns the data or throws an exception. You're not getting the value you want because that function you supply is ignored and you're not capturing the actual return value.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • 4
    The core API pre-dates the modern Promise specification and the adoption of `async`/`await`, so that's a necessary step. The good news is `promisify` usually makes it work with no mess. – tadman Oct 21 '17 at 21:02
  • 1
    This handles the mess of not being able to leverage async-await with FS normally. Thank you for this! You saved me a ton! There is no answer that really addresses this like yours. – jacobhobson Aug 10 '18 at 17:44
  • 4
    Also await is kinda redundant since it can be infered. Only if you do want to explicitly have await in example, you can do `const file = await readFile...; return file;`. – bigkahunaburger Jan 26 '19 at 10:29
  • @tadman do we still need to promisify in latest version of node? – shijin Dec 24 '19 at 07:13
  • 1
    @shijin Until the Node core API switches over to promises, which is unlikely at this point, then yes. There are NPM wrappers that do it for you, though. – tadman Dec 30 '19 at 20:52
64

This is TypeScript version of @Joel's answer. It is usable after Node 11.0:

import { promises as fs } from 'fs';

async function loadMonoCounter() {
    const data = await fs.readFile('monolitic.txt', 'binary');
    return Buffer.from(data);
}
HKTonyLee
  • 3,111
  • 23
  • 34
45

You can use fs.promises available natively since Node v11.0.0

import fs from 'fs';

const readFile = async filePath => {
  try {
    const data = await fs.promises.readFile(filePath, 'utf8')
    return data
  }
  catch(err) {
    console.log(err)
  }
}
arnaudjnn
  • 923
  • 10
  • 12
34

You can easily wrap the readFile command with a promise like so:

async function readFile(path) {
    return new Promise((resolve, reject) => {
      fs.readFile(path, 'utf8', function (err, data) {
        if (err) {
          reject(err);
        }
        resolve(data);
      });
    });
  }

then use:

await readFile("path/to/file");
Shlomi Schwartz
  • 8,693
  • 29
  • 109
  • 186
27

From node v14.0.0

const {readFile} = require('fs/promises');

const myFunction = async()=>{
    const result = await readFile('monolitic.txt','binary')
    console.log(result)
}

myFunction()
MOSI
  • 561
  • 7
  • 8
14

To keep it succint and retain all functionality of fs:

const fs = require('fs');
const fsPromises = fs.promises;

async function loadMonoCounter() {
    const data = await fsPromises.readFile('monolitic.txt', 'binary');
    return new Buffer(data);
}

Importing fs and fs.promises separately will give access to the entire fs API while also keeping it more readable... So that something like the next example is easily accomplished.

// the 'next example'
fsPromises.access('monolitic.txt', fs.constants.R_OK | fs.constants.W_OK)
    .then(() => console.log('can access'))
    .catch(() => console.error('cannot access'));
NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
  • 1
    DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. – mudassirijaz786 Jan 27 '21 at 13:18
3

There is a fs.readFileSync( path, options ) method, which is synchronous.

George Ogden
  • 596
  • 9
  • 15
2
const fs = require("fs");
const util = require("util");
const readFile = util.promisify(fs.readFile);
const getContent = async () => {
let my_content;
try {
  const { toJSON } = await readFile("credentials.json");
  my_content = toJSON();
  console.log(my_content);
} catch (e) {
  console.log("Error loading client secret file:", e);
 }
};
Besufkad Menji
  • 1,433
  • 9
  • 13
2

I read file by using the Promise. For me its properly:

const fs = require('fs')

//function which return Promise
const read = (path, type) => new Promise((resolve, reject) => {
  fs.readFile(path, type, (err, file) => {
    if (err) reject(err)
    resolve(file)
  })
})

//example how call this function
read('file.txt', 'utf8')
    .then((file) => console.log('your file is '+file))
    .catch((err) => console.log('error reading file '+err))

//another example how call function inside async
async function func() {
  let file = await read('file.txt', 'utf8')
  console.log('your file is '+file)
}
Fakt309
  • 821
  • 5
  • 14
  • in your second example, `return` instead of `console.log` will not work because return cannot go with async. – Timo May 24 '22 at 10:07
1

This produces a String from the contents of your file you dont need to use promises for this to work

const fs = require('fs');
const data = fs.readFileSync("./path/to/file.json", "binary");
Ricky Sahu
  • 23,455
  • 4
  • 42
  • 32
0

You can find my approach below: First, I required fs as fsBase, then I put the "promises" inside fs variable.

const fsBase = require('fs');
const fs = fsBase.promises

const fn = async () => {
    const data = await fs.readFile('example.txt', 'utf8');
    console.log(data);
};

fn();
Arin Yazilim
  • 939
  • 8
  • 6
-2

see this example https://www.geeksforgeeks.org/node-js-fs-readfile-method/

// Include fs module
var fs = require('fs');
  
// Use fs.readFile() method to read the file
fs.readFile('demo.txt', (err, data) => {
  console.log(data);
})