How to create a callback function inside the module.exports parameter.
I'm trying to do a similar thing as below and I want to know how to implement callback function.
module.js
module.exports = (a, b, callback) => {
let sum = a+b
let error = null
//callback
}
app.js
const add = require(./module.js)
add(1,2, (err, result) => {
}
within your module.exports you need to "invoke" the call back function.
like so
callback(error, sum)
this will return the control back to the app.js add() function.
You implement your callback function here. i.e what you want to do with the result you received.
Here is what your code will look like:-
module.js
module.exports = (a, b, callback) => {
let sum = a+b
let error = null
callback(error, sum) // invoke the callback function
}
app.js
const add = require("./module")
add(1,2, (err, result) => {
if(err) { // Best practice to handle your errors
console.log(err)
} else { // Implement the logic, what you want to do once you recieve the response back
console.log(result)
}
})
You have used sum for your function; but I will be using divide, because that way I can show you the error thing of callback.
your export will look like this
module.exports = {
divide: (a,b,cb) => {
if (b === 0) {
cb('divide by zero', null);
} else {
cb(null, a/b);
}
}
}
and the import like this
var func = require('./testExport').divide;
func(1,2,(err,res) => {
console.log(err,res);
});
func(1,0,(err,res) => {
console.log(err,res);
})
Call backs are simply the function that you send in from the place you are calling the functions. In both function calls (in imported place) you see we are sending in a function as a callback that takes in two arguments.
In the exported place we call that same function with the first parameter as an error and the second as res.
If you want to import your function without require().func, you will have to export the function in default.
module.exports = (a,b,cb) => {
if (b === 0) {
cb('divide by zero', null);
} else {
cb(null, a/b);
}
}
and import it as
var defaultFunc = require('./testExport')
add.js
module.exports = (a, b, callback) => {
if (typeof a !== 'number' || typeof b !== 'number') {
return callback(new Error('Invalid argument passed'), null);
}
let sum = a + b;
callback(null, sum);
};
app.js
const add = require('./add');
add(1, 2, (err, result) => {
if (err) {
console.log(err);
}
console.log(result);
});
Here we are passing error as the first parameter and actual sum as the second parameter to the callback function. Say if we pass a string instead of the number then the first parameter will have the error object and result will be null.
Cheers.
Related
I'm currently using the prompt package in Node to get user input on the command line, however, I would like to return a variable from prompt.get - how would I store the return variable/where can I access it from? I'm relatively new to Node.
const prompt = require('prompt');
prompt.start();
prompt.get(['num'], function (err: any, result: any) {
if (err) { return Error(err); }
if(result.num > 0) {
return "Positive";
}
else {
return "Negative";
}
});
Cheers!
You could initialize the variable outside the callback, and then set the variable inside of the callback:
let value;
prompt.get(['num'], function (err: any, result: any) {
if (err) { return Error(err); }
value = result > 0 ? "Positive" : "Negative";
});
But the problem is the value will be empty until it's done, so if you try to call it right after, it will be empty.
let value;
prompt.get(['num'], function (err: any, result: any) {
if (err) { return Error(err); }
value = result > 0 ? "Positive" : "Negative";
});
console.log(value); // => undefined
The package also supports promises though, so you can just use await, as shown on their readme:
(async () => {
const { num } = await prompt.get(['num']);
})();
You should notice the anonymous self executing async function, that's because await only works inside of async functions (technically not needed after node v15 & while using modules).
I have declared 'service':
// myService.js
export default {
someService: _.debounce(
function someService(rule, value, callback) {
myApi.get(
`check-input/${value}`,
)
.then((response) => {
if (response.data.valid) {
callback();
} else {
callback(new Error('Invalid value'));
}
})
.catch(() => {
callback(new Error('Internal error. Please try later.'));
});
},2000)};
I would like to use this service two times independently at the same time.
I'm calling this service like this:
const ValidatorA = (rule, value, callback) => {
const serviceA = myService.someService(rule, value, callback);
return serviceA;
};
const ValidatorB = (rule, value, callback) => {
const serviceB = myService.someService(rule, value, callback);
return serviceB;
};
ValidatorA and ValidatorB are linked to different inputs in template and runs almost at the same time. (1s delay)
What I would like to achieve is that ValidatorA and ValidatorB will call myService.someService independently, so there should be two calls at the same time. Currently it calls only once (from ValidatorB as it is called one second later). I suppose that ValidatorB is overwritting call from ValidatorA.
Creating two the same methods is solving this problem, however I believe that there is more elegant solution. Object.assign or _deepClone is not solving problem either.
Thank you!
I think you can wrap someServices in a function
export default {
getServices: function() {
return
_.debounce(
function someService(rule, value, callback) {
myApi.get(
`check-input/${value}`,
)
.then((response) => {
if (response.data.valid) {
callback();
} else {
callback(new Error('Invalid value'));
}
})
.catch(() => {
callback(new Error('Internal error. Please try later.'));
});
},2000)
}
};
and then
const ValidatorA = (rule, value, callback) => {
const serviceA = myService.getServices()(rule, value, callback);
return serviceA;
};
const ValidatorB = (rule, value, callback) => {
const serviceB = myService.getServices()(rule, value, callback);
return serviceB;
};
It might be a bit confusing what I'm asking but I'll try to be as clear as I can.
Basically I'm doing unit test with mocha/chai for my Data Access Layer of my Node.JS server. I'm using bluebird to return a promise and an SQLite Databases.
That's my function insert I want to test :
insert(sqlRequest, sqlParams, sqlRequest2) {
return new Promise(function (resolve, reject) {
let insertStatement = this.getDatabase().prepare(sqlRequest);
let getStatement = this.getDatabase().prepare(sqlRequest2);
insertStatement.run(sqlParams, err => {
console.log('this.changes = ', this.changes);
if (this.changes === 1) {
getStatement.all({ $id: this.lastID }, (err, rows) => {
if (err) {
console.log('entered second err');
reject(err);
} else {
resolve(rows[0]);
}
});
} else {
console.log('entered first err ');
reject(err);
}
});
}.bind(this));
}
And that's my test with mocha :
it('insert : Error 2st SQL query', function (done) {
const daoCommon = new DaoCommon();
daoCommon.getDatabase = () => {
return {
prepare: (sqlRequest) => {
return {
all: (sql, callback) => {
let err = {};
let rows = null;
callback(err, rows);
},
run: (sqlParams, callback) => {
let err = undefined;
callback(err);
}
}
}
}
}
daoCommon.insert('', '', '')
.then(success => {
expect.fail();
})
.catch(error => {
expect(error).to.eql({});
})
.finally(function () {
done();
})
});
I want to simulate a test where the this.changes is equal to 1 but I don't know how/where I can set this value. According to what I've read this this object is from the callback function, but I have no idea exactly from where it comes or how to set it for my tests.
Update:
You can set the this of a function you are calling with .call of the method.
In your case calling callback with this.changes value will look like:
var thisObject = {
changes: 1
};
callback.call(thisObject, err);
This will set the value this.changes of your callback function.
The value of this is explained in the API documentation
If execution was successful, the this object will contain two
properties named lastID and changes which contain the value of the
last inserted row ID and the number of rows affected by this query
respectively.
It means that the callback function will always have this.changes. You can not change it unless you set this.changes = something manually, which I don't understand why would you do that.
Thank for #Maxali comment, I will post the answer below :
You can set this when calling the function callback(err) by using .call(). eg: callback.call({changes:1}, err). this will set changes to 1
And note that I had to change this line insertStatement.run(sqlParams, err => { where I have the callback from an arrow function to a function declaration insertStatement.run(sqlParams, function(err) { for this to work. I assume this is due to the this which in an arrow function doesn't refer to the object inside the function itself.
How I should modify the following code, so I can make sure Process3 is triggered after Process2.update or Process2.create completed?
The main purpose for following code is I want to makeProcess1 finished. Then check if id exist, if yes, Process2.update is triggered. if not, Process2.create is triggered.Once Process2 finished, check if cmd existed. if yes,triggered Process3.
run: function (req, res) {
if (req.session) {
const values = req.params.all();
const id = values.id;
const cmd = values.cmd;
const param = _.omit(values, ['cmd', 'id']);
const cb1 = (e, d) => {
if (e) {
console.log(e);
res.status(400).send({ e });
} else {
Process1(values);
res.status(200).send({ d });
}
};
const cd2 = (id, param, cb1) => {
if (id) {
Process2.update({ id }, param, cb1);
} else {
Process2.create(param, cb1);
}
};
if (cmd) {
cd2(id, param, cb1, Process3(values, cmd));
}
else {
cd2(id, param, cb1);
}
} else {
res.status(403).send({ e: 'Forbidden access.' });
}
}
try approach by following, but not sure how I can pass argument id, params to Process2 and process3
let async = require('async');
const Process1 = (value, cb) => {
console.log("Process1()");
console.log(value);
cb(null, value + 1);
};
const Process2 = (value, cb) => {
console.log("value(): wait 5 sec");
console.log(value);
cb(null, value+10);
};
const Process3 = (value, cb) => {
console.log(value);
console.log("Process3(): wait 5 sec");
cb(null, value+100);
};
let Pro_1_2 = async.compose(Process2, Process1);
let Pro_2_3 = async.compose(Process3, Process2);
Pro_1_2(1, (e, r) => {
Pro_2_3(r, (error, result) => {
console.log(result);
});
});
The code you posted in your original question seems pretty twisted up, so I'm not going to attempt to rewrite it, but in general if you want to perform asynchronous calls which depend on each other, async.auto is a good way to go. Rather than declaring variables at the top that you attempt to mutate via some function calls, it's better to make Process1, Process2 and Process3 asynchronous functions that call their callbacks with a new values object. Something like:
async.auto({
doProcess1: function(cb) {
// Assuming Process1 calls `cb(undefined, newValues)` when done.
Process1(values, cb);
return;
},
doProcess2: ['doProcess1', function(results, cb) {
if (results.doProcess1.id) {
Process2.update({id: results.doProcess1.id}, cb);
return;
} else {
Process2.create(_.omit(results.doProcess1, ['cmd', 'id']), cb);
return;
}
}],
doProcess3: ['doProcess2', function(results, cb) {
if (results.doProcess2.cmd) {
Process3(results.doProcess2, cb);
return;
}
else {
cb(undefined, results.process2);
return;
}
}]
}, function afterProcess3(err, results) {
// Handler err or process final results.
});
Note all the return calls. They're not strictly necessary, but good practice to avoid accidentally running more code after calling your asynchronous functions.
Have you considered using "compose", from async.js?
const a = (data, cb) => {
var result = 'a';
cb(null, result);
};
const b = (data, id, cb) => {
var result = 'b';
cb(null, result);
};
const c = (data, cb) => {
// stuff to do with result
};
var aThenC = async.compose(c, a);
var bThenC = async.compose(c, b);
if (useA) {
aThenC(data, (result) => {
// result from c
res.status(200).send(result);
});
} else {
bThenC(data, id, (result) => {
// result from c
res.status(200).send(result);
});
}
In this scenario, a and b are your Process2 create and update, respectively, and c is the callback to Process3, if I understood correctly.
EDIT: You'll only have to enter the initial parameters (e.g. register ID) on the composed function. What composes really do is this: a(b(c(param))). That param is basically everything you need to start the process. The parameters for the following functions will be set inside the function before that.
I'll add code to support it as soon as I'm on a keyboard.
I'm trying to use Mongoose to pull a random value from a database using Math.random and Mongoose's findOne. Within my function, the value I'm getting is defined; however when I call the function in another class I am receiving an undefined value. I know this is because of Javascript's asynchronous nature, but I'm not sure how to go about fixing this. Any advice would be appreciated!
export const getRandomItem2 = (req, res) => {
var toReturn;
Item.count().exec(function(err, count){
var random = Math.floor(Math.random() * count);
Item.findOne().skip(random).exec(
function (err, result) {
toReturn = result.description;
console.log('toReturn populated here!' + toReturn);
return toReturn; //this is returning undefined
});
});
}
It's asynchronous code, so in another function when You call it You should pass callback function to get the result:
export const getRandomItem2 = (callback) => {
Item
.count()
.exec((err, count) => {
Item
.findOne(Math.floor(Math.random() * count))
.skip(skip)
.exec((err, item) => callback(item));
});
}
and in some another place:
getRandomItem2(item => {
console.log(item);
});