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);
})
Related
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:
Why is my asynchronous function returning Promise { <pending> } instead of a value?
(9 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I have the following piece of code: an endpoint getting the URL of an image, downloading it, resize it, saving it locally, then uploading it to a S3 bucket. Every piece of code works fine on it's own.
// Post a URL of a pic and get a URL of its thumb on AWS S3
router.post("/", (req, res) => {
const url = req.body.url;
const tempPath = './public/uploads/';
const tempFileName = uuidv1();
const createThumbPic = async () => {
const tempURL = tempPath + tempFileName;
jimp.read(url, async (err, img) => {
if (err) {
res.status(400).json({
error: `${err})`,
});
return;
}
img.resize(120, 120)
.quality(60)
.write(tempURL);
});
return tempURL;
}
const uploadThumbnailToS3 = async () => {
const tempURLThumb = await createThumbPic();
const file = await fs.readFileSync(tempURLThumb);
const params = {
Bucket: process.env.S3_BUCKET_ID,
Key: tempFileName,
Body: file
};
// Uploading files to the bucket
const fileUrlOns3 = await s3.upload(params, function (err, data) {
if (err) {
res.status(400).json({ error: err });
}
res.status(201).json({ thumbUrl: resData });
return data.Location;
});
return fileUrlOns3;
}
// Execute Code and respond to client
uploadThumbnailToS3().catch((err) => {
res.status(400).json({ error: err });
});
});
the Error I am getting back from this endpoint:
{
"error": {
"errno": -2,
"syscall": "open",
"code": "ENOENT",
"path": "./public/uploads/imagefiletemp.jpg"
}
}
The problem comes from the follwing to lines: It seems that fs.readFileSyncruns before that createThumbPic() is totally finished. Hence that the readFileSync doesn't find the file it should read, and throw that error back.
const tempURLThumb = await createThumbPic();
const file = await fs.readFileSync(tempURLThumb);
Somehow I know that createThumbPic return tempURLThumb before that the fiel is finished, as I get the response in postman, than 1 sec later I see the file appearing in my directory.
const createThumbPic = async () => {
const tempURL = tempPath + tempFileName;
jimp.read(url, async (err, img) => {
if (err) {
res.status(400).json({
error: `${err})`,
});
return;
}
img.resize(120, 120)
.quality(60)
.write(tempURL);
});
return tempURL;
}
How to make createThumbPicwait until img.resize is completely finished before returning tempURL?
I tried my best learning ASYNC/AWAIT, and thought I had figured, but it seems like something is still off in my code. Any tip?
You need to await your promise:
// upload to S3
const thumbOnS3 = await uploadFileS3(tempURL, tempFileName);
console.log(thumbOnS3)
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 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
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();