I'm trying to use the results of a callback function as properties of an object. Here is how I am trying to use the module I am building:
var Screenshot = require("./Screenshot.js")
const test = async function() {
let screenshot = new Screenshot("./screenshots/Screenshot_20180806093446.jpg")
await screenshot.readScreenshot()
console.log(screenshot.text)
}
test() // logs nothing to console
readScreenshot() doesn't seem to be doing its job. I'm sure there's a finer detail I am missing to making this work.
./Screenshot.js code below:
var tesseract = require("node-tesseract");
module.exports = class Screenshot {
constructor(path) {
this.path = path;
this.readScreenshot = this.readScreenshot.bind(this);
}
readScreenshot() {
tesseract.process(this.path, (err, text) => {
if (err) {
throw err;
} else {
this.text = text.split("\n").filter(el => el.trim() !== "");
}
});
}
};
It would also be nice if I can get the constructor of class Screenshot to properly call this function so I do not have to do it manually in app.js
You will have to change the code so that readScreenshot method allows you to return a promise object.
readScreenshot() {
return new Promise((resolve, reject) => {
tesseract.process(this.path, (err, text) => {
if (err) {
reject(err);
} else {
resolve(text.split("\n").filter(el => el.trim() !== ""))
}
});
});
}
//
var Screenshot = require("./Screenshot.js")
const test = async function() {
let screenshot = new Screenshot("./screenshots/Screenshot_20180806093446.jpg")
let resp = await screenshot.readScreenshot()
console.log(resp)
}
test() // logs nothing to console
Related
I am using the google translate api to translate data from a json file to french locale and then write it back to a file. I am using a recursive function to iterate over the json file since it is deeply nested. However the execution is not waiting till the translation is completed before it writes to the file. I have tried using callback and promise approaches but i couldn't get it right.
Just for it to work as I required an output as an emergency I have set a timout before the write method is called. It work but I would like to learn the appropriate/correct approach to implement this.
const fs = require('fs')
const {Translate} = require('#google-cloud/translate').v2
require('dotenv').config()
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
const credentials = JSON.parse(process.env.credentials)
const translate = new Translate({
credentials,
projectId: credentials.project_id,
})
let data = {}
// writeJSONTofile should be executed only after readJSONFile execution is completed
//read file
const readJSONFile = () => {
try {
data = JSON.parse(fs.readFileSync('...\\locale\\en.json'))
iterateAndTranslate(data)
setTimeout(() => {
writeJSONToFile()
}, 25000)
} catch (error) {
console.log(error)
}
}
// iterate, translate, reassign
const iterateAndTranslate = async (data) => {
for(key in data) {
if (typeof data[key] === 'object' && data[key] !== null) {
iterateAndTranslate(data[key])
} else{
data[key] = await translateText(data[key], 'fr')
}
}
}
//translate method
const translateText = async (text, targetLanguage) => {
try {
let [response] = await translate.translate(text, targetLanguage)
return response
} catch (error) {
console.log(error)
return 0
}
}
const writeJSONToFile = async () => {
var outputFileName = 'C:\\test\\test.json'
await fs.writeFileSync(outputFileName, JSON.stringify(data,null,4), (err) => {
if(err) {
console.log(err)
} else {
console.log('Done!')
}
})
}
// start from here
readJSONFile()
You have a few issues with your code.
Your functions use a global variable and mutate it instead of getting input and returning output.
timeout will cause unexpected behavior in your case.
you are using var
you have redundant async-await on the writeJSONToFile function
See my view of point about the possible solution.
const fs = require("fs");
const { Translate } = require("#google-cloud/translate").v2;
require("dotenv").config();
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
const credentials = JSON.parse(process.env.credentials);
const translate = new Translate({
credentials,
projectId: credentials.project_id,
});
// writeJSONTofile should be executed only after readJSONFile execution is completed
//read file
const readJSONFile = async () => {
try {
const data = JSON.parse(fs.readFileSync("...\\locale\\en.json"));
return iterateAndTranslate(data);
} catch (error) {
console.log(error);
}
return {};
};
// iterate, translate, reassign
const iterateAndTranslate = async (data) => {
for (let key in data) {
if (typeof data[key] === "object" && data[key] !== null) {
await iterateAndTranslate(data[key]);
} else {
data[key] = await translateText(data[key], "fr");
}
}
return data;
};
//translate method
const translateText = async (text, targetLanguage) => {
try {
let [response] = await translate.translate(text, targetLanguage);
return response;
} catch (error) {
console.log(error);
}
return null;
};
const writeJSONToFile = (data) => {
let outputFileName = "C:\\test\\test.json";
fs.writeFileSync(outputFileName, JSON.stringify(data, null, 4), (err) => {
if (err) {
console.log(err);
} else {
console.log("Done!");
}
});
};
// start from here
const run = async () => {
const data = await readJSONFile();
writeJSONToFile(data);
};
run();
See more:
why not using global varible
why not using var
I would like to know to read the files and search for keyword sample in nodejs.
If keyword found, display the path
const allfiles = [
'C:\\Users\\public',
'C:\\Users\\public\\images',
'C:\\Users\\public\\javascripts\\index1.js',
'C:\\Users\\public\\javascripts\\index2.js'
]
const readFile = (path, opts = 'utf8') =>
new Promise((resolve, reject) => {
try{
let result=[];
fs.readFile(path, opts, (err, data) => {
if (err) reject(err)
else {
if(data.indexOf("sample")>=0){
result.push(data);
resolve(result);
}
}
})
}
catch (e) {
console.log("e", e);
}
})
const run = async () => {
allfiles.forEach(e=>{
const s = await readFile(e);
console.log(s);
})
}
run();
Expected Output
[
'C:\\Users\\public\\javascripts\\index1.js',
'C:\\Users\\public\\javascripts\\index2.js'
]
Some tips:
What happens when "sample" isn't found in readFile?
You're currently pushing the data into result instead of the path.
Think about what you're trying to accomplish with readFile. To me, what you want to do is see if that file has the word "sample", and return true if so and if not return false. So I'd name the function checkIfFileHasSample and have it return a boolean. Then in your run function, in the forEach you have the path, so that is where I'd add the path to a list of results.
Maybe you already realized this, but run is never actually called in your code sample. Ie. run() doesn't happen.
Solution:
You had some syntax errors and a tricky gotcha with async-await with run. For the syntax errors, it'll come with experience, but I'd also recommend using ESLint to help you catch them, as well as making sure your code is always properly indented.
const fs = require("fs");
const allfiles = [
"C:\\Users\\public",
"C:\\Users\\public\\images",
"C:\\Users\\public\\javascripts\\index1.js",
"C:\\Users\\public\\javascripts\\index2.js",
];
const checkIfFileHasSample = (path, opts = "utf8") =>
new Promise((resolve, reject) => {
fs.readFile(path, opts, (err, data) => {
if (err) {
reject(err);
} else {
if (data.includes("sample")) {
resolve(true);
} else {
resolve(false);
}
}
});
});
const run = async () => {
const results = [];
for (let i = 0; i < allFiles.length; i++) {
try {
const file = allFiles[i];
const hasSample = await checkIfFileHasSample(file);
if (hasSample) {
results.push(file);
}
} catch (e) {
console.log(e);
}
}
console.log(results);
};
run();
I'm writing a function to verify a url using dns.lookup() function as defined below:
const dns = require('dns');
const verifyURL = (url) => {
const protocolRegEx = /^https?:\/\/(.*)/i;
const hostnameRegEx = /^([a-z0-9\-_]+\.)+[a-z0-9\-_]+/i;
if (url.match(/\/$/i)) {
url = url.slice(0,-1);
}
const protocol = url.match(protocolRegEx);
if (!protocol) {
return false;
}
const hostname = protocol[1].match(hostnameRegEx);
if (hostname) {
dns.lookup(hostname[0], (err, adderss) => {
if (err) return false;
return adderss;
})
}
}
I'm trying to return either true or false from inside of the callback passed to the dns.lookup() function.
(async () => {
let x = await verifyURL('https://stackoverflow.com/')
console.log(x);
})();
But everytime I run this code I get undefined as return value.
I already tried this answer, but it's not working.
Please help me. Thank you!!
You are awaiting a function, verifyURL, which does not return a promise.
One option is to modify your verifyURL function to return a promise.
const verifyURL = (url) => {
const protocolRegEx = /^https?:\/\/(.*)/i;
const hostnameRegEx = /^([a-z0-9\-_]+\.)+[a-z0-9\-_]+/i;
if (url.match(/\/$/i)) {
url = url.slice(0,-1);
}
const protocol = url.match(protocolRegEx);
if (!protocol) {
return false;
}
const hostname = protocol[1].match(hostnameRegEx);
//verify this! I add this to return false if !hostname
if (!hostname) {
return false
}
return new Promise((resolve, reject) => {
dns.lookup(hostname[0], (err, address) => {
if (err) {
return reject(err);
}
// Here I resolve to address. You can resolve to true as you mention in your post.
return resolve(address)
});
});
}
Also you should handle the rejection of the promise.
E.g. looking for https://stackoverflow2.com will give you an error "getaddrinfo ENOTFOUND stackoverflow2.com"
(async () => {
try {
let x = await verifyURL('https://stackoverflow.com')
console.log(x);
} catch (e) {
console.error(e.message)
}
})();
Another option is to use dns promise api
I'm exporting/importing an empty array to implement MVC patern and I was able to successfully store data in it by calling the allMentors method on the Mentor class.
Secondly, I want to be DRY and get the data from the array and then use it to find a specific mentor but I'm getting an empty array.
I searched the internet and I followed the example of using this keyword and call the static method inside another but NodeJS is throwing an error that this is undefined.
ALL MENTORS method
class Mentor{
static async allMentors(req, res) {
try {
users.forEach(user => {
if(user.is_mentor === true) {
mentors.push(user);
}
})
const ObjKeyRename = (src, map) => {
const dst = {};
for (const key in src) {
if (key in map)
// rename key
dst[map[key]] = src[key];
else
// same key
dst[key] = src[key];
}
return dst;
};
const uniqueMentors = Array.from(new Set(mentors.map(m => m.id)))
.map(id => {
return new Promise((resolve, reject)=> {
const currMentor = mentors.find(m => m.id === id);
const modMentor = ObjKeyRename(currMentor, { "id": "mentorId" });
return resolve(modMentor);
})
})
Promise.all(uniqueMentors).then(output => {
output.forEach(async obj => {
await delete obj['password'];
})
return res
.status(200)
.json(new ResponseHandler(200, 'All Mentors', output, null).result());
})
} catch (err) {
return res
.status(500)
.json(new ResponseHandler(500, err.message, null).result());
}
}
static async singleMentor(req, res) {
const returnedMentors = this.allMentors;
console.log('THE RETURNED:',returnedMentors)
const theMentor = returnedMentors.find(u => u.mentorId === parseInt(req.params.mentorId));
try {
if (!theMentor) return res
.status(404)
.json(new ResponseHandler(404, `Mentor number ${req.params.mentorId} not found`, null).result());
return res
.status(200)
.json(new ResponseHandler(200, 'Your mentor', theMentor, null).result());
} catch (err) {
return res
.status(500)
.json(new ResponseHandler(500, err.message, null).result())
}
}
}
export default Mentor;
What am I doing wrong? I appreciate your continued help as a JS learner.
There are multiple problems with your code:
a static method needs to be called by Class (Mentor) not by Reference (this)
a async method needs to be awaited or called with a callback (.then())
So for example you have the class MentorHandler:
class Mentor {
constructor() {
}
static async singleMentor(req, res) {
// ... some more code
}
static async allMentors(req, res) {
// await the result of the method
// call by class
const returnedMentors = await Mentor.allMentors();
// ... some more code
}
}
When a user clicks on a button (#lfdsubmit), it calls the function (LFD_SearchContainer()) that should return a promise. But the errors happens at
LFD_SearchContainer('EISU1870725')
.then(container => {
ST2.db2(container);
})
What is wrong?
Code: (don't completely trust the commented out parts to guide you through this code -- i forgot to update some of them)
function LFDTrack () {
function LFD_SearchContainer (requestedContainer) {
return new Promise((resolve, reject) => {
let lfd_scanparams = { TableName: 'lfd_table1' }
db.scan(lfd_scanparams, (err, containers) => {
if (err) {
reject(err);
} else {
containers = containers.Items;
let requestedContainers = []; // different variable than arg
let containerObject; // this will be the resolved object
// this will return the object of the searched container
let findIt = _.forEach(containers, container => {
if (container.container === requestedContainer) {
containerObject = container;
}
});
containerObject = findIt[0];
//console.log(findIt[0]);
resolve(containerObject.container);
}
});
});
}
$(function() {
$("#lfdsubmit").click(function (e) {
e.preventDefault();
let lsd_modaltitle = $("#lfdmodaltitle");
let lsd_modalcontent = $("#lfdmodalcontent");
LFD_SearchContainer('EISU1870725')
.then(container => {
ST2.db2(container); // will send the object
})
.catch(error => {
console.log(error);
});
});
});
}
If ST2.db2(container); returns a promise, you need to change that line to
return ST2.db2(container);
If it doesn't, you can put return null; behind it, like this:
ST2.db2(container);
return null;
Since you didn't provide the definition for ST2, I can't know whether or not the db2 method returns a promise. :)
The error is explained by the author of bluebird here.