This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm just studying Node.JS, and i have a question over it.
I have to read a file. I do it with 'fs' node and 'fs.readFile()' func.
Here is a code
const fs = require('fs');
let input;
fs.readFile('./'+config.file, (err, data) => {
input = data.toString('utf-8');
});
console.log(input) //!!! it gives me 'undefined' result but i expect file's data
I haven't any ideas how solve this problem. Only i know that this is the async func.
Hope, you will help me :3
Since your code is async, your variable will be logged before the reading of the file is complete.
You can use a function and return a Promise:
const fs = require('fs');
function myReadFile() {
return new Promise((resolve, reject) => {
fs.readFile('myfile.txt', (err, data) => {
if (err) reject(err);
resolve(data.toString());
});
})
}
myReadFile().then((contents) => {
console.log(contents)
});
It is asynchronous so it will first execute the synchronous code that's why input is still undefined. Synchronous code is executed first then async code. Because fs.readFile is async it will get executed after the console.log() in the event loop.
const fs = require('fs');
let input;
fs.readFile('./'+config.file, (err, data) => {
input = data.toString('utf-8');
console.log(input)
});
This should log your input
More on asynchronous code in this article
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 months ago.
I would have a simple question but can't figure it out the answer with Node.JS. Here it is : I got a file with multiple function and I would like to use the return of the first inside the second :
//The first function
const Function1 = (req, res) => {
var axios = require('axios');
var config = {
method: 'get',
url: 'xxxxx.json',
headers: {
//...
}
};
axios(config).then(function(response) {
const array = response.data.datas
return Promise.all(Object.values(array).map(entry => {
return entry.id
}))
}).then(function(response) {
//I got an array with infos
return response
}).catch(function(error) {
console.log(error);
});
}
const Function2 = (req, res) => {
const previousResult = function1()
//Undefined
console.log(previousResult)
}
How should I proceed ?
Thanks a lot
Do you need to call the function?
function1()
Update:
It looks like you added to your question. This now seems to be an issue with async functions. You should look up how to use promises, and async await. It's a bit too complex to describe here, and there are a lot of tutorials about it. The short answer is that when you return inside of a promise, it doesn't return from the outer function1. You could probably test this in your code by putting an explicit return at the end of function1 and you'll see that in console.log().
This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 1 year ago.
I'm new to node.js and I'm struggling with this problem. I don't understand why my output is
ciao
data
data
and not
data
data
ciao
This is my code
fs.readdir("sender", (err, files) => {
if (err) {
throw err;
}
const path = __dirname + "/sender/";
let rawdata = fs.readFileSync(path + "data.json");
var data = JSON.parse(rawdata);
files.forEach((file) => {
fs.stat(path + file, (err, stats) => {
if (err) {
throw err;
}
if (data[file]["size"] != stats.size) data[file]["size"] = stats.size;
if (data[file]["time"] != stats.mtime.toISOString()) data[file]["time"] = stats.mtime.toISOString();
console.log("data");
});
});
console.log("ciao");
});
I've read that foreach is not asynchronous, so I don't really understand why the output is reversed.
forEach is not asynchronous. But the operation you're doing in the forEach callback, fs.stat, is asynchronous.
So what your code is doing is starting a series of fs.stat operations (two, it looks like), then logging ciao, then later when each of those fs.stat operations completes, it's logging data.
You could use the promise-based file system API instead, and use async/await; see comments:
const {readdir, readFile, stat} from "fs/promises";
// This version of `readdir` returns a promise
fs.readdir("sender")
.then(async files => { // Use an `async` function as the fulfillment callback
const path = __dirname + "/sender/";
// Await the promise from `readFile` (no need to use `readFileSync`)
const rawdata = await readFile(path + "data.json");
const data = JSON.parse(rawdata);
// Wait for all operations to complete (they run in parallel)
await Promise.all(files.map(async file => {
// Get the stats (again, awaiting the promise)
const stats = await stat(path + file);
// Update the entry for the file.
const entry = data[file];
if (entry.size != stats.size) { // (There's no point to this comparison, just do the assignment)
entry.size = stats.size;
}
if (entry.time != stats.mtime.toISOString()) { // (Again)
entry.time = stats.mtime.toISOString();
}
console.log("data");
}));
// Since this is after the `await` on the promise from `Promise.all`, it doesn't run until all
// of the promises `Promise.all` was waiting on have been fulfilled
console.log("ciao");
})
.catch(error => {
// ...log/handle error...
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
so I have a function (getBagId) that I want to return the bag id, I know its not returning it due to the async nature, but how would i go about fixing it so it returns the bagId, heres the code
const getBagId = () => {
request.get('https://www.off---white.com/en-us/api/users/me', options, (err, res, data) => {
bagId = data.bagId
})
return bagId
}
once again I want the function to return bagId so the value is set to that, also i want to do this only using callbacks, no promises or async await, thanks
Use request-promise
const getBagId = async () => {
const response = await rp({ uri : 'https://www.off---white.com/en-us/api/users/me' })
// Process the `bagId` from the response (JSON / XML / ??? )
const bagId = // `bagId` from response.
return bagId
}
You could make use of promises:
const getBagId = () => {
return new Promise((res, rej) => {
request.get('https://www.off---white.com/en-us/api/users/me', options, (err, res, data) => {
if(err) return rej(err);
return res(data.bagId);
});
});
}
But now your .getBagId() returns a promise, so you'll have to handle it accordingly in your application
request.get is an asynchronous function, so getById needs to return a promise or to execute asynchronously by using async/await. Otherwise you cannot do it unless there is some version of request.get method that execute synchronously, which I highly doubt that it exists.
This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have the following code that checks the existance of a file and if present, parses the JSON data from it:
fs.access(dbPath, (err) => {
if (err) throw err
else{
console.log('Database found. Processing data.');
dbObj = processDatabaseFile(dbPath);
console.log('checkonstartup: '+dbObj);
return;
}
});
And here is the processDatabaseFile:
function processDatabaseFile(path){
fs.readFile(path, (err, data) =>{
if (err) throw err;
let jsonData = JSON.parse(data);
return jsonData;
})
}
My problem is when the fs.access function is being called, it returns sooner than the processDatabaseFile(dbPath) returns.
Eg. I want to make it use async await, but I don't know how to do that.
Tried putting async (err) => { ... declaration and then using
dbObj = await processDatabaseFile(dbPath) but it gives errors around the if-else and semicolons and missing brackets.
Feedback is appreciated.
EDIT:
About the errors regarding adding async-await. I was using VSCode and it turns out ESLint and JSHint conflicts each other.
You can make fat arrow function async using the syntax below.
const asyncFunc = async () => {
const result = await someAsyncFunc();
}
Promisify fs.readFile(), in Node you get promisify out of the box. Something like
const { promisify } = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
fs.access(dbPath, async (err) => {
if (err) throw err
else {
console.log('Database found. Processing data.');
const dbObj = await processDatabaseFile(dbPath);
console.log('checkonstartup: ' + dbObj);
}
});
async function processDatabaseFile(path) {
const data = await readFileAsync(path);
return JSON.parse(data);
})
I read this article from node
https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/
It says the code below is a process blocker:
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
// moreWork(); will run after console.log
what if I add await?
will the code above becomes non-blocking or it will stay in its true nature?
Example code:
const fs = require('fs');
const data = await fs.readFileSync('/file.md'); // no more blocking
console.log(data);
Thank you
No, the code can't run since await must use in async function.
And await should use for function that return promise.
the code means:
// await new Promise(...)
// console.log(...)
new Promise().then((...) => console.log(...))
If you should non-block function, you should use fs.readFile instead.
Blocking means that the whole application is blocked.
So, all SetInterval, Promise, Events or whatever async callback are paused until that sync function ends its execution.
It's the same of what you get when you use a for..loop.
NodeJS provides you some non-blocking file system methods with callbacks, just change your code like this.
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
console.log(data)
});
There is the only way.
await operator wait a promise, and wrapped in async function
you should code like this
const fs = require("fs");
function readFile(fileName) {
return new Promise((resolve, reject) => {
fs.readFile(fileName, (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
async function f1() {
try {
var x = await readFile("foo.json");
console.log(x);
} catch (e) {
console.log(e); // 30
}
}
f1();