OctaviaLo
OctaviaLo

Reputation: 1396

Execute code after fs.writeFile using async/await

I have a function, startSurvey, which, when run, checks if there are questions in a .json file. If there are no questions, it fetches some questions from Typeform and writes them to the .json file using saveForm. After it writes, I would like to continue executing some code that reads the .json file and logs its contents. Right now, await saveForm() never resolves.

I have promisified the fs.readFile and fs.writeFile functions.

//typeform-getter.js

const fs = require('fs')
const util = require('util')
const fetch = require('cross-fetch')
require('dotenv').config()

const conf = require('../../private/conf.json')
const typeformToken = conf.tokens.typeform

const writeFile = util.promisify(fs.writeFile)

const getForm = async () => {
  const form = await fetch(`https://api.typeform.com/forms/${process.env.FORM_ID}`, {
    headers: {
      "Authorization": `bearer ${typeformToken}`
    }
  }).then(res => res.json())
  const fields = form.fields
  return fields
}

const saveForm = async () => {
  const form = await getForm()
  return writeFile(__dirname + '/../data/questions.json', JSON.stringify(form))
    .then((e) => {
      if (e) console.error(e)
      else console.log('questions saved')
      return
    })
}


module.exports = saveForm

//controller.js

const fs = require('fs')
const util = require('util')
const request = require('request')
require('dotenv').config()

const typeformGetter = require('./functions/typeform-getter')

const readFile = util.promisify(fs.readFile)
const saveForm = util.promisify(typeformGetter)

let counter = 1
const data = []

const getQuestions = async() => {
  console.log('called')
  try {
    let data = await readFile(__dirname + '/data/questions.json')
    data = JSON.parse(data)
    return data
  } catch (e) {
    console.error('error getting questions from read file', e)
  }
}

const startSurvey = async (ctx) => {
  try {
    const questions = await getQuestions()
    if (!questions) await saveForm()
    console.log(questions) //NEVER LOGS
  } catch (error) {
    console.error('error: ', error)
  }
}

startSurvey() //function called

Upvotes: 0

Views: 2781

Answers (1)

Marcos Casagrande
Marcos Casagrande

Reputation: 40394

I don't know your exact error, but there are multiple things wrong with your code:

You're using incorrectly the promisified version of fs.writeFile, if an error occurs, the promise will be rejected, you won't get a resolved promise with an error as the resolved value, which is what you're doing. Use path.join instead of concatenating paths.

In startSurvey, you're using console.log(questions) but that wont have any data if questions.json doesn't exists, which should happen the first time you run the program, since it's filled by saveForm, so you probably want to return the questions in saveForm

So saveForm should look something like this:

const saveForm = async () => {
    const form = await getForm();
    const filePath = path.join(path.__dirname, '..', 'data', 'questions.json');
    await writeFile(filePath, JSON.stringify(form));

    console.log('questions saved');

    return form;          
 }

And startSurvey

const startSurvey = async (ctx) => {
  try {
    const questions = await getQuestions() || await saveForm();
    // This will be logged, unless saveForm rejects
    // In your code getQuestions always resolves
    console.log(questions); 
  } catch (error) {
    console.error('error: ', error)
  }
}

In your controller.js you're using util.promisify on saveForm when it is already a promise.

So it should be:

const saveForm = require('./functions/typeform-getter')

Upvotes: 1

Related Questions