I'm new to node.js, I tried to use setTimeout to simulate long connections and hope it act asynchronously.
var http = require('http');
http.createServer(function (request, response) {
console.log('New request # ' + request.url);
(function (response) {
setTimeout(function () {
console.log('Time is up');
response.writeHead(200, {"Content-Type": "text/plain"});
response.end('Hello World\n');
}, 3000);
})(response);
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
But, the code above perform like a synchronous single thread app, which can only handle one request per 3 seconds.
I thought everything in node.js should act asynchronously. So, what's the problem here?
The SetTimeout is async, you don't need that anonym function in the middle, just write this.
var http = require('http');
http.createServer(function (request, response) {
console.log('New request # ' + request.url);
setTimeout(function () {
console.log('Time is up');
response.writeHead(200, {"Content-Type": "text/plain"});
response.end('Hello World\n');
}, 3000);
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
If you produce 10 concurent request the total comp time will be around 3sec, which means it is async. You can use the ab tool to check, or if you program node, maybe easier to install http-perf. and run nperf -c 10 -n 10 http://127.0.0.1:8124
You need to run your sleep in a new process. There is a module that can help you (https://github.com/cramforce/node-worker) or you can look at the normal api documentaion about spawn.
var async,
__slice = [].slice;
async = require("async");
async.setTimeOut = function() {
var arg, args, callback, delay, runWithTimeOut;
callback = arguments[0], delay = arguments[1], arg = arguments[2], args = 4 <= arguments.length ? __slice.call(arguments, 3) : [];
runWithTimeOut = function() {
return setTimeout(callback, delay, arg, args);
};
return async.parallel([runWithTimeOut]);
};
Related
I have this code. The end event is fired two times. I can't understand why. Any hints? Thanks.
var chance = require('chance').Chance();
require('http').createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
function generateMore() {
while(chance.bool({likelihood: 95})) {
var shouldContinue = res.write(
chance.string({length: (16 * 1024) - 1})
);
if(!shouldContinue) {
console.log('Backpressure');
return res.once('drain', generateMore);
}
}
res.end('\nThe end...\n', function() {
console.log('All data was sent'); // I see this log two times
});
}
generateMore();
}).listen(8080, function () {
console.log('Listening');
});
Because when you open URL, browser tries get favicon.ico and sends two requests to your server.
I have just started with node.js. I find the asynchronous coding style it uses to be very impressive indeed. However, for those of us who are used to Java and Python it does take some time to get used to it.
I know the following code works fine. This is verified by several questions on this forum. I have also tried it on my own.
var http = require('http'),
fs = require('fs');
fs.readFile('./index.html', function (err, html) {
if (err) {
//throw err;
}
http.createServer(function(request, response) {
console.log("Server started");
response.writeHeader(200, {"Content-Type": "text/html"});
response.write(html);
response.write("Other things");
response.end();
}).listen(3000);
});
The way I am interpretting this is as follows:
1. Try reading the html file
i. When done create a server
ii. Send it over to the client
2. Do everything else.
However, we can also have a chain of thoughts as follows:
1. Create the server
2. Try reading the file
i. When done. Send it over to the client
3. In the meanwhile do anything else the server might be asked to do.
The code corresponding to the second chain of thoughts is:
var http = require('http'),
fs = require('fs');
http.createServer(function(request, response) {
console.log("Server started");
response.writeHeader(200, {"Content-Type": "text/html"});
fs.readFile('./index.html', function (err, html) {
if (err) {
//throw err;
}
response.write(html);
response.write("Other things");
});
response.end();
}).listen(3000);
While the first code works as expected. The second one displays nothing at all in the browser.
Why is the second chain of thoughts wrong?
Actually, what happens here is that the following function gets called each time there is an incoming request:
function(request, response) {
console.log("Server started");
response.writeHeader(200, {"Content-Type": "text/html"});
response.write(html);
response.write("Other things");
response.end();
}
You replaced that with:
function(request, response) {
console.log("Server started");
response.writeHeader(200, {"Content-Type": "text/html"});
fs.readFile('./index.html', function (err, html) {
if (err) {
//throw err;
}
response.write(html);
response.write("Other things");
});
response.end();
}
Now here, it will run the following:
Write the header
Queue the readFile
Immediately execute the following: response.end();
By the time it is done reading the file and wants to write the contents, you already ended the response
I am trying to test some some examples from the book I'm reading, "Learning Node 2012". And my application for testing the server by doing 2000 requests is pausing. The tester pauses after 5 requests and sends another 5 after a certain interval. Why is it pausing? How can I fix this?
The server code:
var http = require('http');
var fs = require('fs');
// write out numbers
var counter = 0;
function writeNumbers(res)
{
for (var i = 0; i < 100; i++)
{
counter++;
res.write(counter.toString() + '\n');
}
}
// create the http server
http.createServer( function(req, res) {
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).file + ".txt";
// content header
res.writeHead(200, { 'Content-Type': 'text/plain' } );
// write out numbers
writeNumbers(res);
// timer to open file and read contents
setTimeout(function() {
console.log('opening ' + app);
// open and read in file contents
fs.readFile(app, 'utf8', function(err, data) {
if (err)
res.write('Could not find or open file for reading\n');
else
res.write(data);
res.end();
});
}, 2000);
}).listen(3000);
console.log('Server is running on port 3000');
The spam test code:
var http = require('http');
// the url we want, plus the path and options we need
var options = {
host: 'localhost',
port: 3000,
path: '/?file=secondary',
method: 'GET'
};
var processPublicTimeline = function(response) {
// finished? ok, write the data to a file
console.log('finished request');
};
for (var i = 0; i < 2000; i++)
{
// make the request, and then end it, to close the connection
http.request(options, processPublicTimeline).end();
}
While this definitely does have some relation to Why is node.js only processing six requests at a time?
It is also because you are using a timeOut to call res.end() to close the connection/respond, and thus move onto the next connection in queue.
You should instead think about these types of things aynchronously, without the use of timeOuts, but instead with callBacks.
So your code for your two main blocks could be more like:
var counter = 0;
function writeNumbers(res, callBack){
// notice callBack argument
for (var i = 0; i < 100; i++){
counter++;
res.write(counter.toString() + '\n');
}
// execute callBack (if it exists)
if(callBack && typeof callBack === "function") callBack();
}
http.createServer( function (req, res){
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).file + ".txt";
res.writeHead(200, { 'Content-Type': 'text/plain' } );
writeNumbers(res, function(){
// Notice this function which is passed as a callBack argument for writeNumbers to evaluate.
// This executes when the main writeNumbers portion finishes.
console.log('opening ' + app);
fs.readFile(app, 'utf8', function(err, data) {
if (err)
res.write('Could not find or open file for reading\n');
else
res.write(data);
res.end();
});
});
}).listen(3000);
Notice that your writeNumbers function now takes a callBack argument to execute when it is done, and that when you call it in your server's object, you pass a function as that callBack argument. This is one of the core patterns used very frequently in node.js/javascript applications.
This means that you aren't waiting for a timeOut to execute to end your request response, but rather it is ended as it processes your response, and moves onto the next connection immediately. This is likely to happen wayyyy quicker than 2 seconds (the amount of your timeOut). So you should see your connections being processed much quicker.
Because (as someone pointed out in your comments) your system is only able to handle a few open TCP connections at a time, you want to move through your connections as quickly as possible. Leveraging a callBack chain can help you do that when you want to do things in a certain order, or if you need to wait for certain processes to finish before executing others, without guessing with a timeOut.
Hope this helps!
I wish to create a first node js app. For this I need to pull the public twitter tweet and output tweet as a request response. I searched a lot but I got code that written in older node version code(ie createServer, addListener something like this). How we write code for request a twitter call and output the json as response in node version 0.6.18?
Following is the older code I tried
var http = require("http");
var events = require("events");
var port = 8001;
var twitterClient = http.createClient(80, 'api.twitter.com');
var tweetEmitter = new events.EventEmitter();
var request = twitterClient.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});
function getTweats() {
request.addListener("response", function (response) {
var body = "";
response.addListener("data", function (data) {
body += data;
});
response.addListener("end", function (end) {
var tweets = JSON.parse(body);
if (tweets.length > 0) {
tweetEmitter.emit("tweets", tweets);
console.log(tweets, 'tweets loaded');
}
});
});
request.end();
}
setInterval(getTweats(), 1000);
http.createServer(function (request, response) {
var uri = url.parse(request.url).pathname;
console.log(uri);
if (uri === '/stream') {
var cb = function (tweets) {
console.log('tweet'); // never happens!
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(JSON.stringify(tweets));
response.end();
clearTimeout(timeout);
};
tweetEmitter.addListener("tweets", cb);
// timeout to kill requests that take longer than 10 secs
var timeout = setTimeout(function () {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(JSON.stringify([]));
response.end();
tweetEmitter.removeListener("tweets", cb);
}, 10000);
} else {
loadStaticFile(uri, response);
}
}).listen(port);
console.log("Server running at http://localhost:" + port + "/");
And got error
$ node tweet.js
Server running at http://localhost:8001/
timers.js:223
callback.apply(timer, args);
^
TypeError: Cannot call method 'apply' of undefined
at Timer.ontimeout (timers.js:223:14)
Your error is a common one. Instead of:
setInterval(getTweats(), 1000);
you need
setInterval(getTweats, 1000);
This is because you want setInterval to call the getTweats function itself.
Your code has getTweats() with parentheses instead. This calls getTweats first, and gives the result to setInterval. Since this result is undefined (your function doesn't return anything), node cannot call it.
I'm having a hard time getting node, redis, and async to do what I want. I'm trying very basic things to grasp the patterns of redirecting control flow. Here, I hold a counter variable "success" that increases by one if a comparison key0 > key1 is true. They are static for now so it's always true; the only thing I wish to change is to increment success. I refresh the browser to re-run the comparison and increment success again.
My trouble is: when the page is refreshed, success jumps by 2. I tried putting a callback with incr, but it looks like only get-type commands have callbacks. I have a client.end(); in my script, but it prevented me from reloading the page so I commented it out. I suspect this is the source of my problem. If so, where does client.end belong?
var http = require("http");
var redis = require("redis");
var async = require("async");
client = redis.createClient();
http.createServer(function(request, response) {
// key "success" set to 0 externally, through redis-cli;
client.set("key0", "19");
client.set("key1", "11");
response.writeHead(200, {"Content-Type": "text/plain"});
async.series([
shortcut("key0"),
shortcut("key1"),
shortcut("success")
],
function(err, results){
if (results[0] > results[1]) {
client.incr("success", function(err, reply) {
response.write("incr done");
});
response.write(results[0] + "\n\n");
response.write(results[1] + "\n\n");
response.write(results[2]);
}
response.end();
// client.quit();
});
}).listen(8000);
function shortcut(key) {
return function(callback) {
client.get(key, function(err, reply) {
callback(null, reply);
}
);
}
}
Your browser most likely requests favicon.ico and thus generates the extra request which runs your code a second time.