Here's what I have:
- a Node.js function that performs a long (2-10 seconds) calculation (db + external API calls). I use
async.auto()
to organize my calls' dependencies - a nice visual progress bar on the HTML view page
- a getJSON function calling the query (see code below)
Right now, I'm just updating the progress bar on a timer. But I'd like it to be more accurate. I already broke the server side function to 5 milestones (i.e. after every external call finishes successfully), and I'd like to send that progress info to the client. However, once you res.send(progress)
you complete the response and nothing more could be sent on it.
I obviously need a different pattern here, and I had some ideas:
- 2 ajax calls, one polls for progress and the second gets the results
- one call that gets called 5 times, until the server side function is gone
- Something completely different (maybe long polling, websockets, ?)
The question:
I'd like to know what's the recommended pattern, and how to implement it on both the server and client side. Sample code, or links to samples, are highly appreciated!
And, as always, thanks for your time!
Included here is the code I have so far (with obvious functionality omissions). It's not strictly necessary to answer this question, but I provide it here to give some context.
Client
var searchFunction = function() {
var user = $("#searchTerm").val();
$.getJSON("/search/" + user, function(data) {
console.log(data);
ko.applyBindings(new MyViewModel(data));
});
$("#content").hide();
progressBar(5);
$("#progress_bar").show();
setTimeout(function() {
progressBar(25);
}, 1000);
setTimeout(function() {
progressBar(50);
}, 2000);
setTimeout(function() {
progressBar(75);
}, 3000);
setTimeout(function() {
$("#progress_bar").hide();
$("#content").show();
}, 4000);
};
Server
var searchFunction = function(req, res) {
async.auto({
f1: function(callback) {
//things happen
callback(err, res);
},
f2: function(callback) {
//things happen
callback(err, res);
},
f3: ['f2', function(callback, result) {
//many things happen
callback(err, res);
},
function(err) {
//decisions are made
callback(null, watchers);
}]
}, function(err, result) {
//more exciting stuff happens
res.send(finalResults);
}
);
};
My first thought would be to use socket.io or something similar, with the server emitting an event at each milestone. The client-side version of searchFunction() would simply make the AJAX call and then return, with the socket handler taking care of updating the progress bar.
You could use an event stream to push a percent-complete value back up to the client. But it only works in modern browsers. IE9+ I believe. Here's an example event stream: https://github.com/chovy/nodejs-stream
html
css
client side (jQuery) - listen to /progress event stream
server side - push an event with new progress percent
It would be up to you to define your progress bar in the UI --- I would use a fixed width div with a child that has css rule w/ percentage-based width. That gets updated.