nodejs and expressjs - node.js

app.get('/', function(req, res) {
res.set('Content-Type', 'text/html');
res.send('Yo');
setTimeout(function(){
res.send("Yo");
},1000);
});
It looks like "send" ends the request. How can I get this to write Yo on the screen and then 1 second later (sort of like long polling I guess) write the other Yo to get YoYo? Is there some other method other than send?

Use res.write to generate output in pieces and then complete the response with res.end.

I don't think what you are trying to do is possible.
Once you send a response, the client-server connection will be closed.
Look into sockets (particularly socket.io) in order to keep a connection open and send multiple messages on it.

Try with JQuery+JSON. send the response and then update what ever you need with JQuery and JSON.
This is a good tutorial of expressjs, including DB stuff (mongodb).

If you want to send the result as a single block try
app.get('/', function(req, res) {
res.set('Content-Type', 'text/html');
res.write('Yo');
setTimeout(function(){
res.end("Yo");
},1000);
});
or something like
app.get('/', function(req, res) {
res.set('Content-Type', 'text/html');
var str = 'yo';
setTimeout(function(){
res.end(str + 'yo');
},1000);
});

the thing with node.js is that it relies on an asynchronous "style". so if you introduce something like a "wait" function, you'll lose all the benefits of the asynchronous way of execution.
I believe you can achieve something similar to what you want by:
(asynchronous way) including a function that prints the second "Yo" as a callback to
the first function (or)
(classic wait(synchronous) ) introduce a 'big' loop before presenting the second 'Yo'.
for example:
for(i=0; i < 100000000; i++) {
//do something
}

Related

Override express route handler

I'm trying to redefine a express route handler
I have something like
var x = {
handle: function(req, res){
res.send("first");
}
}
app.post("/handle", x.handle);
setTimeout(function(){
x.handle = function(req, res){
res.send("second");
}
}, 2000)
but this doesn't change the way that route handles requests.
How can I achieve something like this?
A simplest fix is to ensure x.handle is always retrieved. In your approach, the function reference is retrieved once, when you attach it but then when you set the reference to point to another function, the post handler still points to the old one.
Attach then
app.post("/handle", (req, res) => x.handle(req, res) );
This method always asks x for current value of the handle method and you are free to reattach it to anything you want.
why it doesn't work
when you pass x.handle into a method, as a callback, you are not passing a reference to x at all. you are only passing handle around.
later, when you change x.handle, you are changing the handle method for x as expected. but, the previous reference to x.handle as a parameter to your post method is unchanged, because this call to post knows nothing about x. it only knows about the handle method that you passed in.
how to fix it
there are a lot of ways to fix this, depending on how you really want to handle things.
if you just need a timeout, then something like this would work:
var count = 1;
app.post("/handle", function(req, res){
if (count === 1){
setTimeout(function(){
count += 1;
}, 2000);
// do the first thing here
} else {
// do the second thing here
}
});
if you don't need the timeout, you could just increment the count
again, there are a lot of ways to do this... but you will have to include the logic of deciding which one to do, inside of the route handler function directly.

Store settimeout id from nodejs in mongodb

I am running a web application using express and nodejs. I have a request to a particular endpoint in which I use settimeout to call a particular function repeatedly after varying time intervals.
For example
router.get ("/playback", function(req, res) {
// Define callback here ...
....
var timeoutone = settimeout(callback, 1000);
var timeouttwo = settimeout(callback, 2000);
var timeoutthree = settimeout(callback, 3000);
});
The settimeout function returns an object with a circular reference. When trying to save this into mongodb i get a stack_overflow error. My aim is to be able to save these objects returned by settimeout into the database.
I have another endpoint called cancel playback which when called, will retrieve these timeout objects and call cleartimeout passing them in as an argument. How do I go about saving these timeout objects to the database ? Or is there a better way of clearing the timeouts than having to save them to the database. Thanks in advance for any help provided.
You cannot save live JavaScript objects in the database! Maybe you can store a string or JSON or similar reference to them, but not the actual object, and you cannot reload them later.
Edit: Also, I've just noticed you're using setTimeout for repeating stuff. If you need to repeat it on regular intervals, why not use setInterval instead?
Here is a simple solution, that would keep indexes in memory:
var timeouts = {};
var index = 0;
// route to set the timeout somewhere
router.get('/playback', function(req, res) {
timeouts['timeout-' + index] = setTimeout(ccb, 1000);
storeIndexValueSomewhere(index)
.then(function(){
res.json({timeoutIndex: index});
index++;
});
}
// another route that gets timeout indexes from that mongodb somehow
req.get('/playback/indexes', handler);
// finally a delete route
router.delete('/playback/:index', function(req, res) {
var index = 'timeout-' + req.params.index;
if (!timeouts[index]) {
return res.status(404).json({message: 'No job with that index'});
} else {
timeouts[index].cancelTimeout();
timeouts[index] = undefined;
return res.json({message: 'Removed job'});
}
});
But this probably would not scale to many millions of jobs.
A more complex solution, and perhaps more appropriate to your needs (depends on your playback job type) could involve job brokers or message queues, clusters and workers that subscribe to something they can listen to for their own job cancel signals etc.
I hope this helps you a little to clear up your requirements.

How do I make HTTP requests inside a loop in NodeJS

I'm writing a command line script in Node (because I know JS and suck at Bash + I need jQuery for navigating through DOM)… right now I'm reading an input file and I iterate over each line.
How do I go about making one HTTP request (GET) per line so that I can load the resulting string with jQuery and extract the information I need from each page?
I've tried using the NPM httpsync package… so I could make one blocking GET call per line of my input file but it doesn't support HTTPS and of course the service I'm hitting only supports HTTPS.
Thanks!
A good way to handle a large number of jobs in a conrolled manner is the async queue.
I also recommend you look at request for making HTTP requests and cheerio for dealing with the HTML you get.
Putting these together, you get something like:
var q = async.queue(function (task, done) {
request(task.url, function(err, res, body) {
if (err) return done(err);
if (res.statusCode != 200) return done(res.statusCode);
var $ = cheerio.load(body);
// ...
done();
});
}, 5);
Then add all your URLs to the queue:
q.push({ url: 'https://www.example.com/some/url' });
// ...
I would most likely use the async library's function eachLimit function. That will allow you to throttle the number of active connections as well as getting a callback for when all the operations are done.
async.eachLimit(urls, function(url, done) {
request(url, function(err, res, body) {
// do something
done();
});
}, 5, function(err) {
// do something
console.log('all done!');
})
I was worried about making a million simultaneous requests without putting in some kind of throttling/limiting the number of concurrent connections, but it seems like Node is throttling me "out of the box" to something around 5-6 concurrent connections.
This is perfect, as it lets me keep my code a lot simpler while also fully leveraging the inherent asynchrony of Node.

Best way for Node JS to wait on start up for initialisation from database etc

I know Node is non blocking etc but i dont know how to solve this issue without blocking.
You start the server
node app.js
but you need some config etc from a database or mongodb before you deal with incoming requests, so you need to wait for the db response to return before you launch into dealing with taking requests.
I could use nimble but then you have to wrap the routes etc all in a second execution block which is nasty.
Whats the best way?
Node is indeed non-blocking, but that doesn't mean you need to start accepting requests right away! Take a look at the classic HTTP server example:
var http = require('http');
var server = http.createServer(function (req, res) {
// ... logic to handle requests ...
});
server.listen(8000);
You can do anything you like before calling server.listen, including whatever configuration tasks you need. Assuming those tasks are asynchronous, you can start the server in the callback:
var http = require('http');
var server = http.createServer(function (req, res) {
// ... logic to handle requests ...
});
// Set up your mongo DB and grab a collection, and then...
myMongoCollection.find().toArray(function(err, results) {
// Do something with results here...
// Then start the server
server.listen(8000);
});
It is OK to block for things that are necessary. Don't go asynchronous just for the sake of it!
In this case, since the DB is crucial to your app even running, blocking until it is ready is appropriate (and probably saving you a lot of hassle of handling calls that don't have a DB connected yet).
You could also postpone starting your app server (in a callback, promise, etc) until the call to start the DB completes. Though since nothing else is happening until the app is initialized (from what I can tell in the question), it wouldn't matter either way because you're not stealing that single-thread from anything else!
Based on the significance of the server.listen role in the sequence i used nimble and did the following....
In the first block i get the stuff from the db (elastic search in this case) and do some manipulation of it that is required to build the routes in the second block, then in the last block i start the server.
You could use nimble to do some other pre init tasks and just do a parallel block inside the first serial block too.
var chans = [];
flow.series([
function (cb) {
esClient.search({
...
}).then(function (resp) {
var channels = resp.hits.hits;
channels.forEach(function(chan){chans.push(chan.urlSlug)});
chans = chans.join('|');
cb();
});
},
function(cb) {
app.get('/:type('+types+')/[a-z\-]+/[a-z0-9\-]+-:id/', itemRt.feature);//http://localhost:3000/how-to/apple/apple-tv-set-up-tips-3502783/
app.get('/:urlSlug('+types+')/', listingRt.category);
app.get('/:urlSlug('+chans+')/', listingRt.channel);
cb();
},
function(cb) {
server.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
cb();
});
}
]);

Must res.end() be called in express with node.js?

I have several Express applications, and I see that in some modules, res.end() is called at the end of a request handler (after res.send or res.json), while in others, it isn't called.
For example:
app.get('/test', function(req, res) {
res.send('Test', 200);
});
or:
app.get('/test', function(req, res) {
res.send('Test', 200);
res.end();
});
Both cases work, but I'm afraid about leaks or running out file descriptors or something like that, when I run many requests. Which one is "more correct"?
The answer to your question is no. You don't have to call res.end() if you call res.send(). res.send() calls res.end() for you.
Taken from /lib/response.js, here is the end of the res.send() function:
//. . .
// respond
this.end(head ? null : body);
return this;
}
one example where you must call end() function is when you send buffer as a file to download.
res.write(buffer);
res.end();
res.end([data] [, encoding])
Ends the response process. This method actually comes from Node core, specifically the response.end() method of http.ServerResponse.
Use to quickly end the response without any data.
If you need to respond with data, instead use methods such as
res.send() and res.json().

Resources