Reputation:
I am creating and Node project using with MongoDB. I have two files such as change_language.js
and admin_event.js
. I have created a function in change_language.js
file and I called that function from other file (admin_event.js
).
change_language.js
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
var assert = require('assert');
const request = require("request");
const Entity_option = require("../models/entity_option");
var ObjectId = require('mongodb').ObjectID;
require("../routes/admin_event");
function change_language(language_id)
{
let myRes=[];
Entity_option.aggregate([
{$match:{"language_id":ObjectId(language_id)}}
], function (err, result)
{
if (err)
{
myRes=err;
}
else
{
myRes= result;
}
console.log(myRes); // Print 1
})
return myRes;
}
module.exports.change_language = change_language;
admin_event.js
const express = require("express");
const router = express.Router();
const Event = require("../models/event");
const myLan=require("../setting/change_language").change_language;
var ObjectId = require('mongodb').ObjectID;
let language_id="5b9f5b324ae85e12a869187c";
let x = myLan(language_id);
console.log(x); // Print 2
module.exports = router;
The function works as expected. console.log(myRes)
(Print 1 line) shows the output in command prompt. But when I call that function from another file (console.log(x)
) shows undefined
. Why?
Upvotes: 1
Views: 79
Reputation: 4164
As @ponury-kostek said, this is actually a duplicate of a common problem with people who are new to Node.js.
The function change_language
is an async function, but you're returning a value before that async task has had a chance to complete.
What is an async function? Nodejs traditionally uses callbacks which you've already explored here, just with a slight misunderstanding.
Entity_option.aggregate([{
$match:{"language_id":ObjectId(language_id)}
}], function (err, result) {
if (err) {
myRes=err;
}
else {
myRes= result;
}
console.log(myRes); // => 1
})
Here we are making a function call which returns a callback. This callback function (the function that takes an error and result) is not called until the main function (Entity_option.aggregate) finishes. This could be at any time and so you cannot rely on immediately returning any values from the wrapper function. As a result we need to use some nested callbacks to make all of your code async.
In your existing code, you're trying to assign myRes to result, but the return call was outside this callback and so has been called way before this callback has triggered. Which is why you're getting undefined
. Basically, you're not waiting for the async task to complete. It's like putting bread into the toaster, pushing it down but immediately trying to return the toast. It of course isn't ready yet!
Here's a sample of how your code should look.
change_language.js
// All your various requires etc...
function change_language(language_id, callback) {
let myRes=[];
Entity_option.aggregate([{
$match:{"language_id":ObjectId(language_id)}
}], function (err, result) {
if (err) {
myRes=err;
} else {
myRes= result;
}
callback(err, result);
});
}
module.exports.change_language = change_language;
admin_event.js
const express = require("express");
const router = express.Router();
const Event = require("../models/event");
const myLan=require("../setting/change_language").change_language;
var ObjectId = require('mongodb').ObjectID;
let language_id="5b9f5b324ae85e12a869187c";
// Supply a callback as this is an async call
// the callback will be triggered once the async
// process (such as talking to a database) has finished
// or errored.
myLang(language_id, function(err, result) {
let x = result;
console.log(result);
});
module.exports = router;
If we do this, you'll quickly see some issues with callback style code. So I'd point you towards looking at JavaScript "Promises" and async/await, but those are outside the scope of this question.
Upvotes: 1