how to handle exception for promise in loop? - javascript

I am downloading files with zip folder, but it download the zip folder prior to add files in the zip folder object. If I remove them and catch block from call of "this. UrlToPromise ()" it works right, but when it faced reject from "this. UrlToPromise ()" it does not work correctly.
var zip = new JSZip();
zip = this.makezip(files, zip);
zip.generateAsync({ type: "blob" }).then(function (content) {
if (downloadName) {
console.log('zip download one', zip);
FileSaver.saveAs(content, downloadName + '.zip');
} else {
FileSaver.saveAs(content, 'All.zip');
}
});
async makezip(files, zip, folderName = null) {
if (folderName)
var tempFolder = zip.folder(folderName);
for (var i in files) {
files[i].hasOwnProperty('file_title')
if (!Array.isArray(files[i])) {
if (typeof files[i]['file_title'] !== 'undefined' && typeof files[i]['file_path'] !== 'undefined') {
await this.urlToPromise(files[i]['file_path']).then(response=>{
if (!folderName)
zip.file(files[i]['file_title'] + '.' + returnExtFromImage(files[i]['file_path']), response, { base64: true, binary: true });
else
tempFolder.file(files[i]['file_title'] + '.' + returnExtFromImage(files[i]['file_path']), response, { base64: true, binary: true });
})
}
} else if (Array.isArray(files[i])) {
zip = this.makezip(files[i], zip, i);
}
}
return zip;
}
urlToPromise(url) {
return new Promise(function (resolve, reject) {
JSZipUtils.getBinaryContent(url, function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}

Whenever you use reject in a Promise constructor it will trigger the catch method of the Promise instance. Therefore, you need to add a catch handler when you call urlToPromise, like this:
this.urlToPromise(files[i]['file_path']).then(response=>{
if (!folderName)
zip.file(files[i]['file_title'] + '.' + returnExtFromImage(files[i]['file_path']), response, { base64: true, binary: true });
else
tempFolder.file(files[i]['file_title'] + '.' + returnExtFromImage(files[i]['file_path']), response, { base64: true, binary: true });
}).catch(error => {
// do something with the error
})

Use await inside async function instead of then/catch. You can use try catch statement to catch the error.
async makezip(files, zip, folderName = null) {
if (folderName) var tempFolder = zip.folder(folderName);
for (var i in files) {
files[i].hasOwnProperty('file_title');
if (!Array.isArray(files[i])) {
if (
typeof files[i]['file_title'] !== 'undefined' &&
typeof files[i]['file_path'] !== 'undefined'
) {
try {
const response = await this.urlToPromise(files[i]['file_path']);
if (!folderName)
zip.file(
files[i]['file_title'] +
'.' +
returnExtFromImage(files[i]['file_path']),
response,
{ base64: true, binary: true }
);
else
tempFolder.file(
files[i]['file_title'] +
'.' +
returnExtFromImage(files[i]['file_path']),
response,
{ base64: true, binary: true }
);
} catch (error) {
// handle error
}
}
} else if (Array.isArray(files[i])) {
zip = this.makezip(files[i], zip, i);
}
}
return zip;
}

I am answering my own question i was missing await for recursive function.
var zip = new JSZip();
await this.makezip(files, zip).then(zip=>{
zip.generateAsync({ type: "blob" }).then(function (content) {
if (downloadName) {
FileSaver.saveAs(content, downloadName + '.zip');
} else {
FileSaver.saveAs(content, 'All.zip');
}
});
});
async makezip(files, zip, folderName = null) {
/*if folder name exist in props to create new nested folders*/
if (folderName)
var tempFolder = zip.folder(folderName);
for (var i in files) {
files[i].hasOwnProperty('file_title')
if (!Array.isArray(files[i])) {
if (typeof files[i]['file_title'] !== 'undefined' && typeof files[i]['file_path'] !== 'undefined') {
await this.urlToPromise(files[i]['file_path']).then(response=>{
if (!folderName)
zip.file(files[i]['file_title'] + '.' + returnExtFromImage(files[i]['file_path']), response, { base64: true, binary: true });
else
tempFolder.file(files[i]['file_title'] + '.' + returnExtFromImage(files[i]['file_path']), response, { base64: true, binary: true });
}).catch(err=>{
});
}
}
else if (Array.isArray(files[i])) {
/*recursive loop for nested folders files*/
await this.makezip(files[i], zip, i);
}
}
return zip;
}
async urlToPromise(url) {
return await new Promise(function (resolve, reject) {
JSZipUtils.getBinaryContent(url, function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}

That usage of Promise helps you.
function sureify<T, U = Error>(promise: Promise<T>) {
return promise
.then((data) => [data, undefined] as [data: T, error: undefined])
.catch((error: U | undefined) =>
Promise.resolve([undefined, error] as [data: undefined, error: U])
);
}
// Convert from Promise
const [response, error] = await sureify(urlToPromise("url"))

Related

Async function returning existing array as undefined

I have an async function inside my class that does execute like it is supposed, but its return value is undefined when I call it. Executing console.log(array) just before the return line "return array" does work
I've tried setting up the variable in this.array but it is not working either.
class Core {
constructor(key) {
this.key = key;
}
async getSessions() {
var finalresponse = []
try {
// wait for response
await fetch("https://api.purecore.io/rest/1/session/get/?key=" + this.key, { method: "GET" }).then(function (response) {
return response.json();
}).then(function (jsonresponse) {
// looks for errors
if (jsonresponse.error != null) {
throw new Error("PureCore returned an error: " + jsonresponse.error + " -> " + jsonresponse.msg)
} else {
// adds the sessions to the response
jsonresponse.forEach(player => {
finalresponse.push(new CoreSession(player["mojang_username"], player["mojang_uuid"], player["core_id"], player["verified"]))
});
console.log(finalresponse) // returns array list
return finalresponse; // returns undefined
}
});
} catch (e) {
throw new Error("Error while getting the response for 'https://api.purecore.io/rest/1/session/get/?key=" + this.key + "' -> " + e.message)
}
}
}
class CoreSession {
constructor(username, uuid, core_uuid, verified) {
this.username = username;
this.uuid = uuid;
this.core_uuid = core_uuid;
this.verified = verified;
}
}
// testing:
sessions = new Core("731b59d106ea5acd0a385958d8e0f18b4b74b741f28f6efa43ed4a273a42d6f9").getSessions().then(function (value) {
console.log(value)
}, function (reason) {
console.log(reason)
});
I'm getting these results:
(from the chrome debug tool)
you have to return something from the async function,
// wait for response
return await fetch("https://api.purecore.io/rest/1/session/get/?key=" + this.key, { method: "GET" }).then(function (response) {
class Core {
constructor(key) {
this.key = key;
}
async getSessions() {
var finalresponse = []
try {
// wait for response
return await fetch("https://api.purecore.io/rest/1/session/get/?key=" + this.key, { method: "GET" }).then(function (response) {
return response.json();
}).then(function (jsonresponse) {
// looks for errors
if (jsonresponse.error != null) {
throw new Error("PureCore returned an error: " + jsonresponse.error + " -> " + jsonresponse.msg)
} else {
// adds the sessions to the response
jsonresponse.forEach(player => {
finalresponse.push(new CoreSession(player["mojang_username"], player["mojang_uuid"], player["core_id"], player["verified"]))
});
console.log(finalresponse) // returns array list
return finalresponse; // returns undefined
}
});
} catch (e) {
throw new Error("Error while getting the response for 'https://api.purecore.io/rest/1/session/get/?key=" + this.key + "' -> " + e.message)
}
}
}
class CoreSession {
constructor(username, uuid, core_uuid, verified) {
this.username = username;
this.uuid = uuid;
this.core_uuid = core_uuid;
this.verified = verified;
}
}
// testing:
sessions = new Core("731b59d106ea5acd0a385958d8e0f18b4b74b741f28f6efa43ed4a273a42d6f9").getSessions().then(function (value) {
console.log(value)
}, function (reason) {
console.log(reason)
});

NodeJS and Mocha :Test is getting passed, instead of getting failed

Below program is to read all the files under a folder and check if all the files contains email information.
The below test should be failed(i.e.., promise to be rejected and status should be failed) when the condition in the second "if" statement is true. Execution is getting stopped, but the test is getting passed instead of getting failed.
So, How do i make the below test fail.
Thanks in Advance.
var checkFileContent = function(directory) {
var results = [];
fs.readdir(directory, function(err, list) {
// if (err) return done(err);
console.log("The folder or list of file names : " + list);
var i = 0;
(function next()
{
var file = list[i++];
// if (!file) return done(null, results);
file = directory + '/' + file;
fs.stat(file, function(err, stat)
{
if (stat && stat.isDirectory())
{
checkFileContent(file, function(err, res)
{
results = results.concat(res);
next();
});
} else
{
fs.readFile(file, "utf8", function(err, data)
{
// if ( err )
// { throw err;}
console.log(file +" file content is");
console.log(data);
console.log( data.toLowerCase().indexOf('email'));
return new Promise((resolve, reject) => {
if(data.toLowerCase().indexOf('email') != -1)
{
return reject(file + 'contains email ');
}
else
{
return new Promise((resolve, reject) =>
{
fs.readFile(file, "utf8", function(err, data)
{
// if ( err )
// { throw err;}
console.log(file +" file content is");
console.log(data);
console.log( data.toLowerCase().indexOf('email'));
//return newfunc(file,data);
if(data.toLowerCase().indexOf('email') != -1)
{
reject(file + 'contains email ');
}
else
{
console.log(file + 'doesnt contain email');
resolve(true);
}
}).catch ((err) =>
{
//Execution is getting stopped here, but the test is getting passed instead of getting failed.
return reject(err);
});
});
results.push(file);
//console.log("List of files under the current Log folder are : " + results);
next();
} // else closure
}); // fs.stat() closure
})(); });
}
The above function is being called from another JS File using Mocha as shown below :
it('should read Log files', function () {
return ----
.then((abc) => {
------
}).then(()=>
{
return JSFileName.checkFileContent(directory);
}).catch((err) => {
return Promise.reject(err);
})
})

mongoose findone return undefine

I have a bot. It can input some text and return some word.
I would like to use MongoDB. Because Heroku can't store data.
So I add function.js that use mongoose.
console.log('data.functionswitch = ' + data.functionswitch);
console log is work fine. It can reply what i want.
return data.functionswitch;
but return data.functionswitch only return undefined when i call it in input.js/.
I have try async/await.
But it only stops working.
How can I improve it and make it work? Thank you.
-
-
2018/03/15 updated
function.js
function switchfind(id, name, callback) {
mongodb.functionSwitch.findOne({
groupid: id, functionname: name
}, function (err, data) {
if (err) {
console.log(err);
callback(null);
return;
}
else if (!data) {
console.log("No record found")
callback(null);
return;
}
console.log('date = ' + data);
console.log('data.functionswitch = ' + data.functionswitch);
callback(data.functionswitch);
return;
})
};
input.js
function parseInput(rplyToken, inputStr) {
//console.log('InputStr: ' + inputStr);
_isNaN = function (obj) {
return isNaN(parseInt(obj));
}
let msgSplitor = (/\S+/ig);
let mainMsg = inputStr.match(msgSplitor);
let trigger = mainMsg[0].toString().toLowerCase();
exports.mongoose.switchfind(mainMsg[1], mainMsg[2], function (functionswitch) {
console.log('functionswitch = ' + functionswitch)
if (functionswitch === null) {
console.log('HERE === NULL ')
}
if (functionswitch == 0) {
console.log('HERE != 0')
return;
}
else if (functionswitch != 0 ) {
console.log('HERE != 0')
if (inputStr.match(/\w/) != null && inputStr.toLowerCase().match(/\d+d+\d/) != null) return exports.rollbase.nomalDiceRoller(inputStr, mainMsg[0], mainMsg[1], mainMsg[2]);
}
})
}
update
const mongoose = require('mongoose');
let uristring = process.env.mongoURL ||
'mongodb://XXXXXXX';
mongoose.connect(uristring);
mongoose.connect(uristring, function (err, res) {
if (err) {
console.log('ERROR connecting to: ' + uristring + '. ' + err);
} else {
console.log('Succeeded connected to: ' + uristring);
// console.log('allswitch: ' + allswitch);
}
});
var functionSchema = new mongoose.Schema({
groupid: String,
functionname: String,
functionswitch: String
});
// Compiles the schema into a model, opening (or creating, if
// nonexistent) the 'PowerUsers' collection in the MongoDB database
var functionSwitch = mongoose.model('functionSwitchs', functionSchema);
The problem in your code is that you are using findOne as it was synchronous. You cannot simply return the data, you have to use a callback.
Here is a tutorial about callbacks.
Example of what it should look like :
// The find function
function switchfind(id, name, callback) {
mongodb.functionSwitch.findOne({
groupid: id,
functionname: name
}, function (err, data) {
// Handle error
if (err) {
callback(null);
return;
}
// Handle empty data
if (data == null) {
callback(null);
return;
}
// Handle with data
callback(data.functionswitch);
})
};
// How to call it
funcX() {
switchfind(id, name, function (functionswitch) {
if (functionswitch === null) {
// Handle the error
}
// Handle the data
});
}

Again about async/await in javascript

My function looks like this now:
var GetImages = async() => {
var images_array = [];
await request ({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if(error){
console.log('Unable to connect');
}else if(body.meta.status === "ZERO_RESULTS"){
console.log('Uable to find that address.');
}else if(body.meta.status === 200){
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if(photo.original_size.width>photo.original_size.height){
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
//callback(images_array);
}
});
return images_array;
}
I have no idea, how return my array after i'll fill it with values. With callback it works fine, but i wanna do it with async/await methid in right way. Thank you for help.
create method to return promise for request and use that method with await
requestPromise = () => {
return new Promise(function(resolve, reject) {
request({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if (error) {
console.log('Unable to connect');
reject();
} else if (body.meta.status === "ZERO_RESULTS") {
console.log('Uable to find that address.');
reject();
} else if (body.meta.status === 200) {
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if (photo.original_size.width > photo.original_size.height) {
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
resolve(images_array)
}
});
});
}
var GetImages = async() => {
try
{
images = await requestPromise();
return images;
}
catch(e){return [];}
}

Stop or break promises

I am trying to check on an API if a picture It is valid. I am doing it with promises, I want that if a check on API return me a failure, stop execute de promise and call a fuction.
Heres my code.
My function to call the promises
checkPhotos(options,formData, "front", res, false).then(function(response) {
if(response!== 'error'){
options.url = 'http://'+config.verifier_host+':'+config.verifier_port+config.verifier_endpoint_sc;
readImage = fs.createReadStream("tmp/"+imgOne+".jpeg");
formData = {
uuid : request.uuid,
document_type : 1, //req.body.document_type
analysis_type : 1,
document_image: {
value: readImage,
options: {
filename: 'tmp/'+imgOne+'.jpeg',
contentType: null
}
}
};
console.log("2a Ejecución")
return checkPhotos(options,formData, "back", res, false);
}else {
return;
}
}).then(function(response) {
if(response!== 'error'){
options.url = 'http://'+config.verifier_host+':'+config.verifier_port+config.verifier_endpoint_sc;
readImage = fs.createReadStream("tmp/"+nombreImagenBackimg2+".jpeg");
formData = {
uuid : request.uuid,
document_type : 1, //req.body.document_type
analysis_type : 2,
document_image: {
value: readImage,
options: {
filename: 'tmp/'+img2+'.jpeg',
contentType: null
}
}
};
console.log("3a Ejecución")
return checkPhotos(options,formData, "back", res, false);
}else {
return;
}
}).then(function(response) {
if(response!== 'error'){
readImage = fs.createReadStream("tmp/"+nombreImagenSelfieimg3+".jpeg");
formData = {
uuid : request.uuid,
selfie_image: {
value: readImage,
options: {
filename: 'tmp/'+img3+'.jpeg',
contentType: null
}
}
};
options.url = 'http://'+config.verifier_host+':'+config.verifier_port+config.verifier_endpoint_tc;
console.log("4a y última ejecución")
return checkPhotos(options, formData, null, res, true, request);
}else {
return;
}
}).catch(function(err) {
logger.error('PID ' + process.pid + ' Error response' + err.message);
console.log("Catch -> "+ err.message);
});
My function promise.
function checkPhotos (options, formData, positionPhoto, res, bandera, request) {
var promise = new Promise(function (resolve, reject) {
var post_req = requests.post({headers: {Authorization : options.headers.authorization}, url:options.url, formData: formData}, function (err, httpResponse, body) {
if (err) {
logger.error(' PID ' + process.pid + err);
return console.error('Error:', err);
}
if(!body){
logger.error(' PID ' + process.pid + formData.document_image.options.filename);
return false;
}
responseBody = JSON.parse(body);
if(bandera){
if(responseBody.success === 'error'){
resolve(responseBody.success);
return getData(null, res, responseBody);
}else {
resolve(formData);
getData(null, res);
}
}else {
if(responseBody.success === 'error'){
logger.error(' PID ' + process.pid + responseBody);
resolve(responseBody.success);
return getData(null, res, responseBody);
}else {
resolve(formData);
console.log("Success")
}
}
});
});
return promise;
}
Call reject on error instead of resolve. This way the promise chain is immediately rejected and any subsequent calls to .then are not run.
If you want to stop the promise chain from inside a .then call, you can return a Promise.reject(…) value OR throw an error.
Example:
const promise = checkPhotos(...);
promise
.then(askApi)
.then((response) => { throw response.body; })
.then(willNotBeExecuted)
.catch(thisWillbeExecutedAfterThrow);
function checkPhotos (options, formData, positionPhoto, res, bandera, request) {
return (resolve, reject) => {
// … make request
if (!bandera) { reject(getData); }
};
}

Categories

Resources