I have a route in my express app, which is supposed to do the following:
- Get some data from outside (OK)
- Show a HTML page with socket.io listening for messages (OK)
- Perform some calculations, which take a long time
- Send a message trough socket.io after each one one pleted (OK)
- When all calculations are pleted, show a result page (problem)
So, a simplified version of my code is:
module.exports = function(io) { // This is so I can use socket.io inside the route
var express = require('express');
var router = express.Router();
[... and other required]
router.post('/', function(req, res, next) {
res.render('loading'); // This renders the template which holds accepts and renders socket.io messages
pefromCalculaton();
sendSocketIOMessage();
session.data = resultData; // I get the result of all calculations and put that in the session. It's a quick fix, don't judge, I've got no presistancy in my project as for now...
res.redirect('results'); // And here I'd like to go to the other route, which will display the data, getting it from the session.
});
return router;
}
Since this doesn't work, I am probably trying to do something really stupid here. But what I actually want to do is:
- Perform calculations
- While performing the calculations, update progress using sockets
- When calculation is done, render a template, showing all the results.
I have a route in my express app, which is supposed to do the following:
- Get some data from outside (OK)
- Show a HTML page with socket.io listening for messages (OK)
- Perform some calculations, which take a long time
- Send a message trough socket.io after each one one pleted (OK)
- When all calculations are pleted, show a result page (problem)
So, a simplified version of my code is:
module.exports = function(io) { // This is so I can use socket.io inside the route
var express = require('express');
var router = express.Router();
[... and other required]
router.post('/', function(req, res, next) {
res.render('loading'); // This renders the template which holds accepts and renders socket.io messages
pefromCalculaton();
sendSocketIOMessage();
session.data = resultData; // I get the result of all calculations and put that in the session. It's a quick fix, don't judge, I've got no presistancy in my project as for now...
res.redirect('results'); // And here I'd like to go to the other route, which will display the data, getting it from the session.
});
return router;
}
Since this doesn't work, I am probably trying to do something really stupid here. But what I actually want to do is:
- Perform calculations
- While performing the calculations, update progress using sockets
- When calculation is done, render a template, showing all the results.
2 Answers
Reset to default 4Well, my friend, as you know that one can't send two responses from within one request. So here is what you need to do.
module.exports = function(io) { // This is so I can use socket.io inside the route
var express = require('express');
var router = express.Router();
[... and other required]
router.post('/', function(req, res, next) {
var taskId = (new Date()).getTime(); //timestamp to get unique task id.
res.render('loading');
startCalculations(function(progressIndicator){ //progress callback
io.emit('progress',progressIndicator);
},function(result){ // Finish callback
session[taskId] = result;
io.emit('finish',{ taskid: taskId });
});
});
router.get('/result:taskId', function(req, res, next) {
var result = session[req.params.taskId];
if(!result)
{
//Result already consumed!
res.render('expired');
return;
}
delete session[req.params.taskId];
res.render('result', {result: result});
});
//progress callback will be called when we want to report progress
//done callback indicates our results are ready.
function startCalculations(progress, done){
//This is just a stupid piece of code, just to emulate loading.
//Your awesome async code will replace this
//In your case it will not be a loop and there will be a callback
//To signal finish.
var result = 0;
for(i = 0; i < 100; i++)
{
result = result + i;
//Simulate progress
progress(i);
}
//Simulate finish -- result has 0 to 99 all added up ;)
done(result);
}
return router;
}
Now on the html front you can have ...
this is how your
loading
view would look like.
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery./jquery-1.11.1.js"></script>
<script>
var socket = io();
//Init code.
socket.on('progress', function(progressIndicator){
//Your jquery mojo to show progress
displayProgress(progressIndicator);
});
socket.on('finish', function(task){
//Redirect to result page from frontend (you were trying to do
//on backend -- node.js)
window.location.href = "/result/" + task.taskId;
//OR
//window.location.replace("/result/" + task.taskId);
});
</script>
Hope this makes sense and helps ...
Let me know if you need anything else.
Have fun!
Node is asynchronous. Use callbacks or promises to make sure that the result page is shown only when the calculations has been pleted.