Order of function execution in Node async/await - node.js

I have a doubt in making sure the functions run in sequence and the result from the first call is used in second call.
DB Function
async runquery(){
try {
...
const results = await db.statementExecPromisified(statement, []);
return results;
} catch (e) {
console.log("Error - " +JSON.stringify(e));
return e;
}
}
Group id
async function groupByID(approvers) {
const group = _.groupBy(approvers, 'ID');
return Object.keys(group).map(ID=> {
return group[ID].reduce((approvers, cur, idx) => ({
...approvers,
['NAME' + (idx + 1)]: cur.ID,
}), { ID});
})
Final Function
async function preparePayload() {
if(levels.length != 0 ){
let statement= `SELECT * FROM ITEMS `
list = await runquery(statement) ;
id = await groupByID(list) ;
}
let result={}
result.ID=id;
}
Output from DB : [{ID:1,NAME:'F1'},{ID:2,NAME:'F2'},{ID:1,NAME:'F3'}]
Expected Output : [{ID:1,NAME1:'F1',NAME2:'F2'},{ID:2,NAME:'F2'}]
But the output is not coming as expected.
[{
"ID": "2"
},
{
"ID": "1"
}]
I am guessing this is due to sequence of the function execution because when i do console.log(id) works as expected but when i assign to the result variable it gives unexpected output.
I am not sure if I put the question correctly .Kindly let me know if it needs to be more detail.

I don't see anything wrong with your code apart from two small changes
groupByID doesn't need to be async and hence don't need to be awaited
['NAME' + (idx + 1)]: cur.ID, needs to be changed to ['NAME' + (idx + 1)]: cur.NAME,
For simplicity I have removed the db call and replaced it with a promise which returns the result which you have mentioned in your post.
See the working code here - https://repl.it/repls/PepperyGrossForms
It gives me this result
{
ID: [ { ID: '1', NAME1: 'F1', NAME2: 'F3' }, { ID: '2', NAME1: 'F2' } ]
}
Hope this helps.

Related

Use async await with Array.map not working

I've used this approach, it should give me the Expected Output which I've mentioned below.
But, due to asynchronous execution, it is giving the Actual Output.
So, Please help me to solve the same.
See, I'm calling one async function, inside i'm running three nested map loops. And in the third loop I'm connecting the database and fetching values. Based on the value, I'm generating the values of the Object which is empty at the first. And once the function called, it is triggering the then method.That's where the problem arises, I need that then function to be executed after the called function executed completely. This is the complete problem statement
Given the following code:
let messageObject = {};
async function storeManager() {
// storing the defects or modifying
console.log('hii from storeManager()');
await Promise.all(
Object.keys(filledDefects).map((defectName) => {
Object.keys(filledDefects[defectName]).map((subDefectName) => {
Object.keys(filledDefects[defectName][subDefectName]).map(
async (zone) => {
const result = await dbConnectedPool.query(
`SELECT * FROM defect_table WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone = ${zone.replace(
'_',
''
)}`
);
if (result.rows.length == 0) {
// block to save defects record for the first time
console.log(
`INSERT INTO defect_table (body_number,mode,category,subcategory,defect,subdefect,zone,defectCount,date,time,username) VALUES (${enteredBodyNumber},'${mode}','${selectedCategory}','${selectedSubCategory}','${defectName}','${subDefectName}',${zone.replace(
'_',
''
)},${
filledDefects[defectName][subDefectName][zone]
},'${date}','${time}','${username}');`
);
await dbConnectedPool.query(
`INSERT INTO defect_table (body_number,mode,category,subcategory,defect,subdefect,zone,defectCount,date,time,username) VALUES (${enteredBodyNumber},'${mode}','${selectedCategory}','${selectedSubCategory}','${defectName}','${subDefectName}',${zone.replace(
'_',
''
)},${
filledDefects[defectName][subDefectName][zone]
},'${date}','${time}','${username}');`
);
mod.set(
messageObject,
`Newly Saved Zone.${zone}.${defectName}.${subDefectName}`,
filledDefects[defectName][subDefectName][zone]
);
console.log('inside: ', messageObject);
} else {
// block to modify existing defect records
console.log(
`UPDATE defect_table SET defectCount=${
filledDefects[defectName][subDefectName][zone]
},date='${date}',time='${time}',username='${username}' WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone=${zone.replace(
'_',
''
)}`
);
await dbConnectedPool.query(
`UPDATE defect_table SET defectCount=${
filledDefects[defectName][subDefectName][zone]
},date='${date}',time='${time}',username='${username}' WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone=${zone.replace(
'_',
''
)}`
);
mod.set(
messageObject,
`Overwritten Zone.${zone}.${defectName}.${subDefectName}`,
filledDefects[defectName][subDefectName][zone]
);
console.log('inside: ', messageObject);
}
// checking whether already record exists with same aspects
}
);
});
})
);
console.log('bye from storeManager()');
}
storeManager().then(() => {
console.log('message outside:', messageObject);
});
Expected Output:
hii from storeManager()
bye from storeManager()
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth'
WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH
SBML' AND defect='Surface' AND subdefect='Dent' AND zone=210
inside: { 'Overwritten Zone': { _210: { Surface: [Object] } } }
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth'
WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH
SBML' AND defect='Surface' AND subdefect='Dent' AND zone=215
inside: {
'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}
message outside: {
'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}
Actuall Output:
hii from storeManager()
bye from storeManager()
message outside: {}
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth'
WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH
SBML' AND defect='Surface' AND subdefect='Dent' AND zone=210
inside: { 'Overwritten Zone': { _210: { Surface: [Object] } } }
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth'
WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH
SBML' AND defect='Surface' AND subdefect='Dent' AND zone=215
inside: {
'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}
You'll need to use Promise.all everywhere you are producing an array of promises, not just on the outermost call. And you'll need to make the map callbacks actually return those promises!
await Promise.all(Object.entries(filledDefects).map(async ([defectName, defect]) => {
await Promise.all(Object.entries(defect).map(async ([subDefectName, subDefect]) => {
await Promis.all(Object.entries(subDefect).map(async ([zoneName, zone]) => {
await …;
}));
}));
}));
Alternatively you can also write this without some of the async/await:
await Promise.all(Object.entries(filledDefects).map(([defectName, defect]) =>
Promise.all(Object.entries(defect).map(async ([subDefectName, subDefect]) =>
Promis.all(Object.entries(subDefect).map(async ([zoneName, zone]) => {
await …;
}));
));
));
Promise.all expects an array of promises as argument, but you pass it an array of undefined values instead. That means Promise.all will return a promise that is resolved immediately.
Two causes for this problem:
the outer map callbacks don't have a return statement (so they map each defectName and each subDefectName to undefined)
If you would return the result of the inner .map calls, then each defectName maps to an array (of arrays ...), which still isn't what you need. You don't want a nested array, but a flat array, so use return Object.keys().flatMap instead of Object.keys().map

Elasticsearch node js point in time search_phase_execution_exception

const body = {
query: {
geo_shape: {
geometry: {
relation: 'within',
shape: {
type: 'polygon',
coordinates: [$polygon],
},
},
},
},
pit: {
id: "t_yxAwEPZXNyaS1wYzYtMjAxN3IxFjZxU2RBTzNyUXhTUV9XbzhHSk9IZ3cAFjhlclRmRGFLUU5TVHZKNXZReUc3SWcAAAAAAAALmpMWQkNwYmVSeGVRaHU2aDFZZExFRjZXZwEWNnFTZEFPM3JReFNRX1dvOEdKT0hndwAA",
keep_alive: "1m",
},
};
Query fails with search_phase_execution_exception at onBody
Without pit query works fine but it's needed to retrieve more than 10000 hits
Well, using PIT in NodeJS ElasticSearch's client is not clear, or at least is not well documented. You can create a PIT using the client like:
const pitRes = await elastic.openPointInTime({
index: index,
keep_alive: "1m"
});
pit_id = pitRes.body.id;
But there is no way to use that pit_id in the search method, and it's not documented properly :S
BUT, you can use the scroll API as follows:
const scrollSearch = await elastic.helpers.scrollSearch({
index: index,
body: {
"size": 10000,
"query": {
"query_string": {
"fields": [ "vm_ref", "org", "vm" ],
"query": organization + moreQuery
},
"sort": [
{ "utc_date": "desc" }
]
}
}});
And then read the results as follows:
let res = [];
try {
for await (const result of scrollSearch) {
res.push(...result.body.hits.hits);
}
} catch (e) {
console.log(e);
}
I know that's not the exact answer to your question, but I hope it helps ;)
The usage of point-in-time for pagination of search results is now documented in ElasticSearch. You can find more or less detailed explanations here: Paginate search results
I prepared an example that may give an idea about how to implement the workflow, described in the documentation:
async function searchWithPointInTime(cluster, index, chunkSize, keepAlive) {
if (!chunkSize) {
chunkSize = 5000;
}
if (!keepAlive) {
keepAlive = "1m";
}
const client = new Client({ node: cluster });
let pointInTimeId = null;
let searchAfter = null;
try {
// Open point in time
pointInTimeId = (await client.openPointInTime({ index, keep_alive: keepAlive })).body.id;
// Query next chunk of data
while (true) {
const size = remained === null ? chunkSize : Math.min(remained, chunkSize);
const response = await client.search({
// Pay attention: no index here (because it will come from the point-in-time)
body: {
size: chunkSize,
track_total_hits: false, // This will make query faster
query: {
// (1) TODO: put any filter you need here (instead of match_all)
match_all: {},
},
pit: {
id: pointInTimeId,
keep_alive: keepAlive,
},
// Sorting should be by _shard_doc or at least include _shard_doc
sort: [{ _shard_doc: "desc" }],
// The next parameter is very important - it tells Elastic to bring us next portion
...(searchAfter !== null && { search_after: [searchAfter] }),
},
});
const { hits } = response.body.hits;
if (!hits || !hits.length) {
break; // No more data
}
for (hit of hits) {
// (2) TODO: Do whatever you need with results
}
// Check if we done reading the data
if (hits.length < size) {
break; // We finished reading all data
}
// Get next value for the 'search after' position
// by extracting the _shard_doc from the sort key of the last hit
searchAfter = hits[hits.length - 1].sort[0];
}
} catch (ex) {
console.error(ex);
} finally {
// Close point in time
if (pointInTime) {
await client.closePointInTime({ body: { id: pointInTime } });
}
}
}

Unable to write item(s) to DynamoDB table utilizing DocumentClient - Nodejs

I'm absolutely brand new to DynamoDb and I'm trying to simply write an object from a NodeJS Lambda. Based on what I've read and researched I should probably be using DocumentClient from the aws-sdk. I also found the following question here regarding issues with DocumentClient, but it doesn't seem to address my specific issue....which I can't really find/pinpoint unfortunately. I've set up a debugger to help with SAM local development, but it appears to be only providing some of the errors.
The code's implementation is shown here.
var params = {
TableName: "March-Madness-Teams",
Item: {
"Id": {"S": randstring.generate(9)},
"School":{"S": team_name},
"Seed": {"S": seed},
"ESPN_Id": {"S": espn_id}
}
}
console.log(JSON.stringify(params))
dynamodb.put(params, (error,data) => {
if (error) {
console.log("Error ", error)
} else {
console.log("Success! ", data)
}
})
Basically I'm scrubbing a website utilizing cheerio library and cherry picking values from the DOM and saving them into the json object shown below.
{
"TableName": "March-Madness-Teams",
"Item": {
"Id": {
"S": "ED311Oi3N"
},
"School": {
"S": "BAYLOR"
},
"Seed": {
"S": "1"
},
"ESPN_Id": {
"S": "239"
}
}
}
When I attempt to push this json object to Dynamo, I get errors says
Error MultipleValidationErrors: There were 2 validation errors:
* MissingRequiredParameter: Missing required key 'TableName' in params
* MissingRequiredParameter: Missing required key 'Item' in params
The above error is all good in well....I assume it didn't like the fact that I had wrapped those to keys in strings, so I removed the quotes and sent the following
{
TableName: "March-Madness-Teams",
Item: {
"Id": {
"S": "ED311Oi3N"
},
"School": {
"S": "BAYLOR"
},
"Seed": {
"S": "1"
},
"ESPN_Id": {
"S": "239"
}
}
}
However, when I do that...I kind of get nothing.
Here is a larger code snippet.
return new Promise((resolve,reject) => {
axios.get('http://www.espn.com/mens-college-basketball/bracketology')
.then(html => {
const dynamodb = new aws.DynamoDB.DocumentClient()
let $ = cheerio.load(html.data)
$('.region').each(async function(index, element){
var preregion = $(element).children('h3,b').text()
var region = preregion.substr(0, preregion.indexOf('(') - 1)
$(element).find('a').each(async function(index2, element2){
var seed = $(element2).siblings('span.rank').text()
if (seed.length > 2){
seed = $(element2).siblings('span.rank').text().substring(0, 2)
}
var espn_id = $(element2).attr('href').split('/').slice(-2)[0]
var team_name = $(element2).text()
var params = {
TableName: "March-Madness-Teams",
Item: {
"Id": randstring.generate(9),
"School":team_name,
"Seed": seed,
"ESPN_Id": espn_id
}
}
console.log(JSON.stringify(params))
// dynamodb.put(params)
// .then(function(data) {
// console.log(`Success`, data)
// })
})
})
})
})
Can you try without the type?
Instead of
"School":{"S": team_name},
for example, use
"School": team_name,
From your code, I can see the mis promise on the dynamodb request. Try to change your lines :
dynamodb.put(params).then(function(data) {
console.log(`Success`, data)
})
to be :
dynamodb.put(params).promise().then(function(data) {
console.log(`Success`, data)
})
you can combine with await too :
await dynamodb.put(params).promise().then(function(data) {
console.log(`Success`, data)
})
exports.lambdaHandler = async (event, context) => {
const html = await axios.get('http://www.espn.com/mens-college-basketball/bracketology')
let $ = cheerio.load(html.data)
const schools = buildCompleteSchoolObject(html, $)
try {
await writeSchoolsToDynamo(schools)
return { statusCode: 200 }
} catch (error) {
return { statusCode: 400, message: error.message }
}
}
const writeSchoolsToDynamo = async (schools) => {
const promises = schools.map(async school => {
await dynamodb.put(school).promise()
})
await Promise.all(promises)
}
const buildCompleteSchoolObject = (html, $) => {
const schools = []
$('.region').each(loopThroughSubRegions(schools, $))
return schools
}
const loopThroughSubRegions = (schools, $) => {
return (index, element) => {
var preregion = $(element).children('h3,b').text()
var region = preregion.substr(0, preregion.indexOf('(') - 1)
$(element).find('a').each(populateSchoolObjects(schools, $))
}
}
const populateSchoolObjects = (schools, $) => {
return (index, element) => {
var seed = $(element).siblings('span.rank').text()
if (seed.length > 2) {
seed = $(element).siblings('span.rank').text().substring(0, 2)
}
var espn_id = $(element).attr('href').split('/').slice(-2)[0]
var team_name = $(element).text()
schools.push({
TableName: "March-Madness-Teams",
Item: {
"Id": randstring.generate(9),
"School": team_name,
"Seed": seed,
"ESPN_Id": espn_id
}
})
}
}
I know this is drastically different from what I started with but I did some more digging and kind of kind of worked to this...I'm not sure if this is the best way, but I seemed to get it to work...Let me know if something should change!
Oh I understand what you want.
Maybe you can see the code above works, but there is one concept you have to improve here about async - await and promise especially on lambda function.
I have some notes here from your code above, maybe can be your consideration to improve your lambda :
Using await for every promise in lambda is not the best approach because we know the lambda time limitation. But sometimes we can do that for other case.
Maybe you can change the dynamodb.put method to be dynamodb.batchWriteItem :
The BatchWriteItem operation puts or deletes multiple items in one or more tables.
Or If you have to use dynamodb.put instead, try to get improve the code to be like so :
const writeSchoolsToDynamo = async (schools) => {
const promises = schools.map(school => {
dynamodb.put(school).promise()
})
return Promise.all(promises)
}

How to get value from module, returns undefined value

I am trying to return a random number from the random-number-csprng API and it sends the value to the console, but not outside of the module. How can I compare the value from the module inside another module?
I have tried to return the number parameter from the .then() function but it still does not get outside of the function.
const Promise = require("bluebird");
const randInt = require("random-number-csprng");
class project {
constructor(uname) {
this.uname = uname;
}
randomNumber(lowest, highest)
{
Promise.try(() => {
return randInt(lowest, highest);
}).then(number => {
console.log("Your random number:", number);
}).catch({code: "RandomGenerationError"}, err => {
console.log("Something went wrong!");
});
}
checkRandom()
{
console.log(`This is a test: ${this.randomNumber(1,100)}`);
if(this.randomNumber(1, 100) > 1)
{
console.log(`Works!`);
}
else
{
console.log(`Does not work!`);
}
}
}
Output
This is a test: undefined
Your random number: 65
Your random number: 71
I expected the output to be 65 on the undefined log, but seems like it does not get stored outside of the Promise.try()
I see you followed the example code on their documentation a bit too literally. You need to return the promise from the method, and consume it asynchronously by awaiting it:
const randInt = require('random-number-csprng');
class Project {
constructor(uname) {
this.uname = uname;
}
randomNumber(lowest, highest) {
return randInt(lowest, highest);
}
async checkRandom() {
const randomValue = await this.randomNumber(1,100);
console.log(`This is a test: ${randomValue}`);
if (randomValue > 1) {
console.log('Works!');
} else {
console.log('Does not work!');
}
}
}

How to return an array of errors with graphQL

How can I return multiple error messages like this ?
"errors": [
{
"message": "first error",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"somePath"
]
},
{
"message": "second error",
"locations": [
{
"line": 8,
"column": 9
}
],
"path": [
"somePath"
]
},
]
On my server, if I do throw('an error'), it returns.
"errors": [
{
"message": "an error",
"locations": [
{
}
],
"path": ["somePath"]
}
]
I would like to return an array of all the errors in the query.
How can I add multiple errors to the errors array ?
Throw an error object with errors:[] in it. The errors array should have all the errors you wanted to throw together. Use the formatError function to format the error output. In the below example, I am using Apollo UserInputError. You can use GraphQLError as well. It doesn't matter.
const error = new UserInputError()
error.errors = errorslist.map((i) => {
const _error = new UserInputError()
_error.path = i.path
_error.message = i.type
return _error
})
throw error
new ApolloServer({
typeDefs,
resolvers,
formatError: ({ message, path }) => ({
message,
path,
}),
})
//sample output response
{
"data": {
"createUser": null
},
"errors": [
{
"message": "format",
"path": "username"
},
{
"message": "min",
"path": "phone"
}
]
}
Using ApolloServer I've found multiple errors will be returned when querying an array of items and an optional field's resolver errors.
// Schema
gql`
type Foo {
id: ID!
bar: String # Optional
}
type Query {
foos: [Foo!]!
}
`;
// Resolvers
const resolvers = {
Query: {
foos: () => [{ id: 1 }, { id: 2 }]
}
Foo: {
bar: (foo) => {
throw new Error(`Failed to get Foo.bar: ${foo.id}`);
}
}
}
// Query
gql`
query Foos {
foos {
id
bar
}
}
`;
// Response
{
"data": {
"foos": [{ id: 1, bar: null }, { id: 2, bar: null }]
},
"errors": [{
"message": "Failed to get Foo.bar: 1"
}, {
"message": "Failed to get Foo.bar: 2"
}]
}
If Foo.bar is not optional, it will return just the first error.
If you want to return many errors, at once, I would recommend MultiError from VError which allows you to represent many errors in one error instance.
You would need to catch the errors without the throw statement because you don't want to interrupt your process. Instead, you can create an array called errors and .push() the errors into it. When you see fit, near the end of your process, you can check to see if there are errors inside the errors array. If there are, you can display them or handle them as you wish
// example
var errors = [];
doSomething(function(err,res){
if(err){
errors.push(err);
}
console.log("we did a thing");
doSomethingElse(function(err,res2){
if(err){
errors.push(err);
};
console.log("we did another thing");
// check and throw errors
if(errors.length > 0){
throw errors;
}
});
});
You can use the GraphQL Error Function, I have a example with TypeScript:
function throwError(message: string, path: any) {
throw new GraphQLError(
message,
[],
{body: '', name: ''},
undefined,
[path]
)
}
And then I just call the function as many times as needed.
The JavaScript constructor looks like:
constructor(
message: string,
nodes?: $ReadOnlyArray<ASTNode> | ASTNode | void,
source?: ?Source,
positions?: ?$ReadOnlyArray<number>,
path?: ?$ReadOnlyArray<string | number>,
originalError?: ?Error,
extensions?: ?{ [key: string]: mixed },
): void;
Check the graphql-js gitHub:
https://github.com/graphql/graphql-js/blob/master/src/error/GraphQLError.js#L22
Looks like the question it is not about to show many exceptions but about to show all the stack trace of the error. When one error is thrown up, the execution will not receive or throw up other error. In some languages, you can nativally set the parent exception to the current exception, but it is not the case of javascript, so far I can tell and looking to the docs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error and https://nodejs.org/api/errors.html#errors_error_propagation_and_interception. You will need to create your own error class, what it is not that hard.
If the problem it is show trace
The stack trace in Javascript it is a string! What it is good if you just want to put it into some log but bad if you want to make a more meaningful reading structure, like a json.
If what you want to do it is really show the stack trace, probably you are going to need to convert the stack trace of the Error object into an array, using something like this:
https://github.com/stacktracejs/error-stack-parser and then put this array inside of your error object.
After that, you can just save that object into your database. You still will be watching just one error, but you are going to have all the "location", "line", "path" of it trace, that sounds to me what you are looking for.
If the problem it is to show the parent errors message and trace
If you want to keep the parent Error of some trace, you will probably need to create your own error class.
/**
* Class MyError extends Error but add the parentError attribute
*/
function MyError(message, parentError ) {
this.message = message;
this.stack = Error().stack;
this.parentError = parentError;
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.name = "MyError";
function a() {
b();
}
function b() {
try {
c();
} catch ( e ) {
throw new MyError( "error on b", e );
}
}
function c() {
d();
}
function d() {
throw new MyError("error on d");
}
function showError( e ) {
var message = e.message + " " + e.stack;
if ( e.parentError ) {
return message + "\n" + showError( e.parentError );
}
return message;
}
try{
a();
} catch ( e ) {
console.log(showError( e ));
}
If the problem it is show many errors messages and trace
If you want to keep many errors into a big package, for validation feedback, for example, you may extend the error class to create a package of errors. I created one simple example of each one of this classes.
/**
* Class MyErrorPackage extends Error
* but works like a error package
*/
function MyErrorPackage(message, parentError ) {
this.packageErrors = [];
this.message = "This package has errors. \n";
this.isValid = true;
this.stack = Error().stack;
this.parentError = parentError;
this.addError = function addError( error ) {
this.packageErrors.push( error );
this.isValid = false;
this.message += "PackageError(" + this.packageErrors.length + "): " + error.stack + error.stack + "\n";
};
this.validate = function validate() {
if( ! this.isValid ) {
throw this;
}
};
}
MyErrorPackage.prototype = Object.create(Error.prototype);
MyErrorPackage.prototype.name = "MyErrorPackage";
function showError( e ) {
var message = e.message + " " + e.stack;
if ( e.parentError ) {
return message + "\n" + showError( e.parentError );
}
return message;
}
function showPackageError( e ) {
var message = e.message + " " + e.stack;
if ( e.parentError ) {
return message + "\n" + showError( e.parentError );
}
return message;
}
try{
var p = new MyErrorPackage();
try {
throw new Error("error 1");
} catch( e1 ) {
p.addError(e1);
}
try {
throw new Error("error 2");
} catch( e2 ) {
p.addError(e2);
}
try {
throw new Error("error 3");
} catch( e3 ) {
p.addError(e3);
}
p.validate();
} catch ( e4 ) {
console.log(showError( e4 ));
}

Resources