After download the Zip file I need to call another function to ProcessZip file. But am unable to trigger the function ProcessZipFile() after the .send():
app.get('/', function (req, res) {
DownloadZipFile();
});
function DownloadZipFile() {
var file = fs.createWriteStream('./tmp/student.tar.gz');
s3.getObject(params
.on('httpData', function (chunk) {
file.write(chunk);
})
.on('httpDone', function () {
file.end();
})
.send();
}
function ProcessZipFile() {
//.....
}
As far as I know you can't call functions after you send a response to the browser. Because the route is finished. I have 2 ideas for you.
1: Make your DownloadZipFile() as a middleware and at success you go to ProcessZipFile() and then send the response()
2: Make a new route where you call ProcessZipFile() and call this route from the frontend via ajax for example
NodeJS is designed to be non-blocking, which means most I/O operations are asynchronous. You cannot simply call ProcessZipFile() after the .send() because this will trigger ProcessZipFile() before the download completes. Instead, you should call the function inside the success event handler which will be executed when the download completes.
function downloadZipFile(s3Params, downloadPath, callback) {
const file = fs.createWriteStream(downloadPath);
s3
.getObject(s3Params)
.on('httpData', function(chunk) {
file.write(chunk);
})
.on('success', function() {
// download succeeded -> execute the callback to proceed
callback(null);
})
.on('error', function(err) {
// download failed -> execute the callback to notify the failure
callback(err);
})
.on('complete', function() {
// close the file regardless of the download completion state
file.end();
})
.send();
}
function processZipFile(filePath, callback) {
// Process the file
// Remember to call `callback` after completion
}
app.get('/', function (req, res) {
const s3Params = { ... };
const filePath = './tmp/student.tar.gz';
downloadZipFile(s3Params, filePath, function(err) { // this callback function will be executed when the download completes
if (err) {
res.status(500).send('Failed to download the file.');
} else {
processZipFile(filePath, function(err) { // this callback function will be executed when the file is processed
if (err) {
res.status(500).send('Failed to process the file.');
} else {
res.send('File is downloaded and processed.');
}
});
}
});
});
Related
How can I put res in a normal function i.e not an exported one which is not part of routes?
function createNewStudent(v,callBackOne){
if (callBackOne) {
studentInfo.callBackOneStudent = callBackOne;
}
// common filter json
var filterjson = common.defaultFilterJson();
filterjson['active'] = true;
filterjson['email'] = v.email;
// student initialization
var student = new Student(v);
async.waterfall([
function (done) {
student.save(function (err) {
if (!err) {
studentInfo.callBackOneStudent();
Employee.update({_id: student.created_by},{"$push": { "students": student._id } }).exec(function (err, employee) { });
done();
}
});
}
}
});
},
function (done) {
var url = config.mailer.studentActivateUrl + student._id;
---error is here-----
res.render('modules/users/server/templates/student-confirmation-email', {
name: student.first_name + ' ' + student.last_name,
appName: 'GAIPP',
url: url
}, function (err, emailHTML) {
done(err, emailHTML, student);
});
}
});
My error is 'res' is not defined. Can anyone please help me to solve this error?
The only way that you can put res in a function is if you somehow supply it to that function at runtime. Remember that res is meaningful only in request handling. Outside of the request handler your function couldn't even know which request to respond to because there might be several requests served at the same time.
If you want to have a function that has access to res then you have those options:
Use a nested function in your request handler, e.g.
app.get('/foo', function (req, res) {
function x() {
// you can use res here
}
x();
});
Add res as an argument:
function x(res) {
// you can use res here
}
app.get('/foo', function (req, res) {
x(res);
});
Another option would be to add a callback to your function that would be passed by the handler:
function x(args, cb) {
// you cannot use res here
// but you can call the callback:
cb(null, 'something');
}
app.get('/foo', function (req, res) {
x(function (err, data) {
if (err) {
// handle error
}
// use res here with data supplied by x()
res(data);
});
});
Instead of using callback your x() function could also return a promise.
I'm using node.js code to create a function to download an image from A repository and then upload to B repository. I want to force all streams to complete before it continues with other tasks. I have tried this way, but I have not been successful.
Example: When I run it, it will run into getImage. When getImage is not completed, it will loop through A->B->C until they are complete and then it completes getImage. How can I force all streams to complete before it continues with other tasks? I mean I want getImage to be finished before running A->B->C.
PS: I am using pkgCloud to upload the image to IBM Object Storage.
function parseImage(imgUrl){
var loopCondition = true;
while(loopCondition ){
getImages(imgUrl,imgName);
Do task A
Do task B
Do task C
}
}
function getImages(imgUrl, imgName) {
//Download image from A repository
const https = require('https');
var imgSrc;
var downloadStream = https.get(imgUrl, function (response) {
// Upload image to B repository.
var uploadStream = storageClient.upload({container: 'images', remote: imgName});
uploadStream.on('error', function (error) {
console.log(error);
});
uploadStream.on('success', function (file) {
console.log("upload Stream>>>>>>>>>>>>>>>>>Done");
console.log(file.toJSON());
imgSrc = "https://...";
});
response.pipe(uploadStream);
});
downloadStream.on('error', function (error) {
console.log(error);
});
downloadStream.on('finish', function () {
console.log("download Stream>>>>>>>>>>>>>>>>>Done");
});
return imgSrc;
}
You should understand the difference between sync and async function. The getImages function is executing async code and therefore if you want to use the results of this function you have to pass a callback that will be called when the streaming will finish. Something like that:
function parseImage(imgUrl) {
getImages(imgUrl, imgName, function (err, imgSrc) {
if (imgSrc) {
Do task A
} else {
Do task B
}
});
}
function getImages(imgUrl, imgName, callback) {
//Download image from A repository
const https = require('https');
var imgSrc;
var downloadStream = https.get(imgUrl, function (response) {
// Upload image to B repository.
var uploadStream = storageClient.upload({ container: 'images', remote: imgName });
uploadStream.on('error', function (error) {
console.log(error);
return callback(error);
});
uploadStream.on('success', function (file) {
console.log("upload Stream>>>>>>>>>>>>>>>>>Done");
console.log(file.toJSON());
imgSrc = "https://...";
return callback(null, imgSrc);
});
response.pipe(uploadStream);
});
downloadStream.on('error', function (error) {
console.log(error);
return callback(error);
});
downloadStream.on('finish', function () {
console.log("download Stream>>>>>>>>>>>>>>>>>Done");
});
}
I have a request handler for a particular route that does something like the following:
function doThing(req, res) {
res.json({ "thing" : "thing", "otherThing": externalModule.someFunction("yay"); });
}
It seems like the result is being send before the "someFunction" call completes, so the "otherThing" JSON is always non-existent. How can I wait for that function to return data before sending a response?
Use callbacks. Example:
externalModule.someFunction = function(str, cb) {
// your logic here ...
// ... then execute the callback when you're finally done,
// with error argument first if applicable
cb(null, str + str);
};
// ...
function doThing(req, res, next) {
externalModule.someFunction("yay", function(err, result) {
if (err) return next(err);
res.json({ "thing" : "thing", "otherThing": result });
});
}
When I have a simple function processing the request I can use res.end() and return to end it at any point (some error happened/incorrect data, etc.)
get('/', function (req, res) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end(); // <-- response is ready, send it to client
return; // <-- request processing stops here, get() finishes
}
// do other stuff
res.send('ok'); // <-- this can never overlap with the previous res.send()
});
However, if there are functions embedded in other functions, return will only quit the last one
get('/', function (req, res) {
validate(req);
// do other stuff
res.send('ok'); // <-- this can cause errors? res was ended already
});
function validate(req, res) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end(); // <-- send response to client
return; // <-- this one exists only from validate()
}
}
I believe to send the response to client res.end() should be called, but how can I stop further code from processing - i.e. return from all functions?
It is impossible to return from a called function, just use a callback as below:
function validate(req, res, callback) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end();
} else {
callback();
}
}
get('/', function (req, res) {
validate(req, function () {
res.send('ok');
});
});
You could return true or false in validate function depending on if you had already sent response.
But, it's not node style. Using callbacks is preferred in node.
I know this is an old question but may be helpful for others. You could use res.headersSent like this
get('/', function (req, res) {
validate(req);
// will only be sent if validate hasn't already sent the error message
if(!res.headersSent) {
res.send('ok');
}
});
function validate(req, res) {
if (!req.param('id')) {
res.send('Must provide ID!');
res.end();
}
}
Running into async hell again with the following inner callback in a test I am writing. I've commented the callback that doesn't wait. I'm using both an async.series to marshall the functions, and async.each to keep the inner iteration synchronous. Mocha compalins "done() was called multiple times" - why isn't the code waiting?
describe('Report Generation (R subsystem)', function () {
before(function (done) {
//clear test files
async.series([function (callback) { //1st
console.log('Delete local test files');
_.each(output_file_template, function (test_file) {
if (fs.existsSync(__dirname + '/../reports/' + test_file + user_file_code + '.png')) {
fs.unlinkSync(__dirname + '/../reports/' + test_file + user_file_code + '.png');
};
}); //..._.each
callback();
}, function (callback) { //2nd
console.log('Delete remote test files');
async.each(output_file_template, function (test_file, cb) {
console.log(test_file);
s3.del('reports/' + test_file + user_file_code + '.png', function (err, res) {
console.log("Delete err", err);
console.log("Delete result", res);
cb();
}, function(err) {callback(err);}); //s3.head
}); //...async.each
}], function (err, res) { //3rd
done(); //this should tell the begin() clause to complete
}); //...async.series
}); //...before
it('should not start this test until before() has finished!', function (done) {
console.log("1st test here");
});
});
, What I can see is, you are doing async.series with an array of 3 functions, but no controlling function at the end.
I assume, your code in it('should not start... is the one which should be in there.
So (I think) your code should look like this:
describe('My Test 1', function () {
//clear test files
async.series([
function (callback) { //1st
console.log('Delete local test files');
...
callback();
},
function (callback) { //2nd
console.log('Delete remote test files');
async.each(
output_file_template,
function (test_file, cb) {
console.log(test_file);
s3.del('reports/' + test_file + user_file_code + '.png', function (err, res) { //I can't get the following nested callback to wait
console.log("Delete err", err);
console.log("Delete result", res);
cb();
}); //...s3.head
},
function( err ) { // this is the control function for async.each, so now it waits after all s3 have finished
callback( err );
}
); //...s3.head
},
function (callback) { //3rd -> will be called now after the async.each (I don't think, you use it so can be deleted anyway)
callback();
}
],
function( err, result ) {
done(); // whatever this has to do with the last "it" -> here is the point, where the "before" is completely done
}
});
I didn't test the source, so maybe there are typos inside, but I think it shows the picture.