21

I am doing some really simple testing regarding reading csv files into a json format using the csvtojson node module, I used the code below as a template

a,b,c
1,2,3
4,5,6
*/
const csvFilePath='<path to csv file>'
const csv=require('csvtojson')
csv()
.fromFile(csvFilePath)
.then((jsonObj)=>{
    console.log(jsonObj);
    /**
     * [
     *  {a:"1", b:"2", c:"3"},
     *  {a:"4", b:"5". c:"6"}
     * ]
     */ 
})
 
// Async / await usage
const jsonArray=await csv().fromFile(csvFilePath);

I am mostly focusing on the

// Async / await usage

const jsonArray=await csv().fromFile(csvFilePath);

Section of the code. Right so here is my code

// const JSONtoCSV = require("json2csv")
// const FileSystem = require("fs")

async function test()
{
    const data = await CSVtoJSON().fromFile('./input.csv')
    return data
}

let temp = await test()

console.log(temp)

and ever which way I have tried it I always get the following error

let temp = await test()
           ^^^^^

SyntaxError: await is only valid in async functions and the top level bodies of modules
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1031:15)
    at Module._compile (node:internal/modules/cjs/loader:1065:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
    at node:internal/main/run_main_module:17:47

or

const data = await CSVtoJSON().fromFile('./input.csv');
             ^^^^^

SyntaxError: await is only valid in async functions and the top level bodies of modules
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1031:15)
    at Module._compile (node:internal/modules/cjs/loader:1065:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
    at node:internal/main/run_main_module:17:47

if I switch the code to be all top level like so

const CSVtoJSON = require("csvtojson")
// const JSONtoCSV = require("json2csv")
// const FileSystem = require("fs")

const data = await CSVtoJSON().fromFile('./input.csv')

console.log(data)

I can't see why this isn't working.

EDIT: I made the change as @tasobu noted. Now all I get is a returned promise

const data = (async () => {
    return await CSVtoJSON().fromFile('./input.csv')
})

console.log(data)
Debugger attached.
Promise { <pending> }
Waiting for the debugger to disconnect...
Ataxote
  • 323
  • 1
  • 2
  • 8
  • The error message is pretty clear: is your code a module? is your `await` inside of an `async` function? If the answer is "no" then that is the problem. – Pointy Sep 07 '21 at 13:55
  • Why does `csvtojson` provide a JS object, and not json? – evolutionxbox Sep 07 '21 at 13:55
  • You can only use await in an async function. You've used it outside one in let temp = await test() – Invizi Sep 07 '21 at 13:55
  • Does this answer your question? [Javascript / Nodejs use await on top level in nodejs module](https://stackoverflow.com/questions/56380592/javascript-nodejs-use-await-on-top-level-in-nodejs-module) – derpirscher Sep 07 '21 at 13:57
  • As Invizi said replace `let temp = await test()` by `let temp = test()` – Patfreeze Sep 07 '21 at 13:57
  • Wrap your whole code in an `async` IIFE. Read more [here](https://stackoverflow.com/a/40746608/5605822) – Tasos Sep 07 '21 at 13:58
  • @Patfreeze that would make `temp` to be a promise. How would that solve the problem? – derpirscher Sep 07 '21 at 13:58
  • @derpirscher you're right. Missing the `then` like `let temp = test().then(data => data)` – Patfreeze Sep 07 '21 at 14:06

5 Answers5

25

You can use an IIFE here (Read more about it here)

(async function main () {
    // You can use await inside this function block
})();
theekshanawj
  • 485
  • 5
  • 9
7

A Promise return something in the future so you need a way to wait for it.

// const CSVtoJSON = require("json2csv")
// const FileSystem = require("fs")
let temp = undefined;

async function test()
{
    const data = await CSVtoJSON().fromFile('./input.csv')
    // do your stuff with data
    
    temp = data;

    console.log(temp) // at this point you have something in.
    return true
}

test();
console.log(temp) // at this point nothing was there.
Patfreeze
  • 680
  • 6
  • 16
  • 1
    Thank you for this. I understand that a number of the answers here are the same and provide the same solution, This answer gives me the details that allow me to better understand this. – Ataxote Sep 07 '21 at 21:53
6

Put your whole code into an async function and call it, so you won't have any thing other than some const statements and function/class declarations outside of the function:

async function main () {
  // All code here, can use await
}

main().then(() => process.exit(0), e => { console.error(e); process.exit(1) })
CherryDT
  • 25,571
  • 5
  • 49
  • 74
3

Other solutions:

  • Add "type": "module" into package.json, and replace all const x = require('x') with import x from 'x'. If you don't/can't have package.json (e.g. a script in /usr/bin/), then change file's extension from .js to .mjs. By the way: node script.mjs works, node script doesn't (it says "Cannot find 'script'"). Tested with Node.js 16.15.0 LTS and 18.2.0.
  • Or use TypeScript.
Arzet Ro
  • 487
  • 1
  • 5
  • 12
-2

You have to just leave out the await section, if you don't want to use it.

const csvFilePath = "./data.csv"
const csv = require("csvtojson")
csv()
  .fromFile(csvFilePath)
  .then((jsonObj) => {
    console.log(jsonObj)
  })

// Async / await usage
//const jsonArray = await csv().fromFile(csvFilePath)

Or:

// Async / await usage
async function csvToJson() {
  const res = await csv().fromFile(csvFilePath)
  console.log(res)
}

csvToJson()
  • 1
    I would actually preffer to use the ASYNC AWAIT section. I don't really like miles of .then().then().then satements. Aditionally I want to be able to take the result of the csv file and then use it multiple times in later iterations of the code – Ataxote Sep 07 '21 at 14:09
  • 1
    It's not to nice to vote down, but I wrote (edit) the async for you. – Sütemény András Sep 07 '21 at 14:15
  • People are allowed, supposed and encouraged to vote up or down as they think and please, there is nothing not nice about it, it's how the site works. By the way, your solution will cause unhandled promise rejections in case anything fails, it'd best to point out that a `.catch` is required at the point where the async function is called from the non-async context. – CherryDT Sep 07 '21 at 14:52
  • I just rewrite the template code... (no ".catch")... both of my solution is getting the right result... thank you for lighten me up about voting system, however I still not think it's fair, but I get used to it. – Sütemény András Sep 07 '21 at 18:52