Home > Enterprise >  How to add text sequentialy to a file with javascript
How to add text sequentialy to a file with javascript

Time:03-17

I have this code:

const fs = require("fs");

const saveFile = (fileName, data) => {
  return new Promise((resolve) => {
    fs.writeFile(fileName, data, (err) => {
      resolve(true);
    });
  });
};

const readFile = (fileName) => {
  return new Promise((resolve) => {
    fs.readFile(fileName, "utf8", (err, data) => {
      resolve(data);
    });
  });
};

const filename = "test.txt";

saveFile(filename, "first");

readFile(filename).then((contents) => {
  saveFile(filename, contents   " second");
});

readFile(filename).then((contents) => {
  saveFile(filename, contents   " third");
});

I'm hoping to obtain in 'test.txt'

first second third

but instead, I get

first thirdd

The idea is that every time I receive a certain post request. I have to add more text to the file

Does someone have any solution for this?

Thank you so much!

CodePudding user response:

Because these are async functions they notify you that the work is completed in the then function.
That means you want to use a then chain (or an async function) like so:

readFile(filename).then((contents) => {
  return saveFile(filename, contents   " second");
}).then(() => {
  return readFile(filename)
}).then((contents) => {
  saveFile(filename, contents   " third");
});

CodePudding user response:

To anyone wondering what's happening here, this is because of asynchronicity in JavaScript. The following code:

saveFile(filename, "first");

readFile(filename).then((contents) => {
  saveFile(filename, contents   " second");
});

readFile(filename).then((contents) => {
  saveFile(filename, contents   " third");
});

...is essentially interpreted by the interpreter like this:

saveFile(filename, "first")
readFile(filename)
readFile(filename)

This is because these calls happen sequentially and start asynchronous contexts called promises. So, the file gets saved and then is read twice right away. Two promises are made and they each execute in the order that they were created. So the first promise gets executed, and then the second promise gets executed:

(contents => {
  saveFile(filename, contents   " second");
})()
(contents => {
  saveFile(filename, contents   " third");
})()

The issue here is that contents is identical because readFile was invoked twice right after saving.

By chaining the promises together you can avoid this altogether:

saveFile(filename, "first")
  .then(() => readFile(filename))
  .then(contents => saveFile(filename, contents   " second"))
  .then(() => readFile(filename))
  .then(contents => saveFile(filename, contents   " third"))

Or you can use async/await, which is even easier to read:

async function start() {
  let contents
  await saveFile(filename, "first")
  contents  = await readFile(filename)
  await saveFile(filename, contents   " second")
  contents  = await readFile(filename)
  await saveFile(filename, contents   " third")
}

start()

I'll add one last refactor to all of your code, because I'm bored.

import { promisify } from "util";
import * as fs from "fs";

const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);

const filename = "test.txt";
async function appendFile(str) {
  let contents = "";
  if (fs.existsSync(filename)) contents = await readFile(filename, "utf8");
  await writeFile(filename, `${contents} ${str}`);
}

["first", "second", "third"].reduce(async (promise, contents) => {
  await promise;
  return await appendFile(contents);
}, Promise.resolve());
  • Related