I have a simple function which routes a HTTP query pattern, queries redis and sends a response. The following is the code
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname,function(err,obj){
console.log("the response from redis is ",obj)
cache.put(eventname,obj);
console.log("inserting to cache");
this.res.end(obj); // this object is root cause for all problems
});
}
The router object afaik, sends the response using this.res.end(obj) . I guess since I am trying to do this inside my redis client , I am getting error. Is there any other way to send the value as a response ? I thought of using emitter based model where the channel emits the response and listener gets it. but it feels like a round about way to solving this problem. Is there any simpler approach ?
The error may be because, where you're trying to use this, it doesn't have the intended value -- an object with a res property that in turn has an end() method.
That would be because every function in JavaScript has its own this with its own value. And, when nesting functions, using this will return the value for the closest function (i.e. shadowing).
To resolve that, you can save the intended value to a local variable:
router.get('/getinfo/:teamname', function main(teamname) {
var request = this;
rclient.hgetall(teamname,function(err,obj){
// ...
request.res.end(obj);
});
});
Or, bind the anonymous callback so both functions are forced to have the same this value:
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname, function(err,obj){
// ...
this.res.end(obj);
}.bind(this));
});
Related
my requirements are to send an object method as a response using express. This is so that I can create dynamic onClick js code in front-end.
const data = {
message: "Hi",
click: () => {
console.log("Hello world");
}
};
res.send(data);
I tried to send it, but the method won't send. The log for the above sample code in front-end JS is as below.
{message: "Hi"}
My workaround was to send the whole function as a string and then use Function Constructor to parse the string. It worked, but I read other forum entries where it said it is very bad practice to parse a string as a function.
Kindly suggest the ways through which I can solve this problem.
You basically have two choices:
Use the Function constructor as you are. It's fine if you can trust who you're getting the string from that you're converting into code. What you shouldn't do is use it when you don't need to convert a string to a function (e.g., there's a better way), or with a string from a source you can't trust.
Don't send dynamic handlers at all. Instead, have a set of standard handlers in a script that you include in your page:
const handlers = {
sayHi() {
alert("Hello world");
},
doSomething() {
// ...
},
doSomethingElse() {
// ...
}
};
and send back the name of a handler ("sayHi", "doSomething", "doSomethingElse") rather than the code of the handler. Then you use the handler via handlers[name].
I'm working on a Meteor project and want to get the return value of Meteor.call in template helpers on client side. At very first, I just set a variable in the call back function and get the variable's value outside the Meteor.call. I found out the code after Meteor.call doesn't execute at all. Then I searched a bit and use Session, it works. But I don't really understand the reason. Here's my original code and modified code. Can anyone explain a bit for me? Thanks!!
Original wrong code: html
<div id="text-result-main">
<h2>{{title}}</h2>
</div>
js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
console.log(titles);
return titles;
}});
Collection text.js
Text = new Mongo.Collection("text");
Meteor.methods({
'getTitle': function(myindex){
return Text.findOne({index: myindex}).title;
}});
The working code: js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
Session.set("titles",result);
});
console.log(Session.get("titles"));
return Session.get("titles");
}});
Notice that I didn't publish Collection Text to the client at all because it's just so huge. Every time when I refresh the page when running the wrong code, I can't see the content of "title" or see it on the console. But when I set the session, it works. I don't really understand how it works here. Thanks
There is two issues Asynchronicity and Reactivity
This affectation
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
inside the meteor call is executed but in a asynch way. So the return of your helper is immediately called, and return a empty value.
Try it out in the console of your browser.
But then, why your template render correctly with {{title}} when you use a Session Variable ?
It's because the Session is a reactive data source, witch means that every change to it trigger a re-computation of all templates involving this piece of data.
Here is a timeline:
Methods is called
Return empty value
Method is executed, setting variable value
If the Variable is a reactive data source, template is re-computed. ( in your case, the session is a reactive data source. )
To go further
I would use a reactive var in that case, it's very close from a session variable, but the scope is limited to a template.
A good read on Reactive data source: http://richsilv.github.io/meteor/meteor-reactive-data-types/
The problem is the fact that Meteor.call() is asynchronous when paired with a callback.
So when title() starts executing, it does not wait for your Meteor.call() invocation to return a result (or possibly an error). It continues execution. This is called asynchronous execution.
In short, you are trying to log the value for the key titles which doesn't exist in Session (since the state of your asynchronous Meteor call is unknown, at this point of time).
Try moving the console log statement into the callback paired with your Meteor.call() and you can see the result once it has successfully been set in Session.
A workaround to your problem is to make your Meteor.call() synchronous like this:
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
var result = Meteor.call('getTitle', index); // <--- this is synchronous code now
Session.set("titles",result);
console.log(Session.get("titles"));
return Session.get("titles");
}});
Removing the callback makes Meteor.call() behave synchronously.
If you do not pass a callback on the server, the method invocation
will block until the method is complete. It will eventually return the
return value of the method, or it will throw an exception if the
method threw an exception.
(from http://docs.meteor.com/api/methods.html#Meteor-call)
Why not use something like this:
title: function(){
var index = Router.current().params.index;
var a = Text.findOne({index: myindex}).title;
console.log(a);
return a;
without methods
In express.js when we call
app.get(function(req,res){...}),
the function automatically receives request and response objects and we can give any name to function parameters like req,res or re,rs and many others.
I want to create a function that will rest in an object.
When I want to use this function it must receive default arguments which may be e.g simple int 4,3 and I must be able to specify parameter names as per my choice.And these arguments must be assigned to parameter names I have defined and I must be able to use those name in code inside function.
How can I achieve this?
You can write your own middleware for this. For example this is how I control the mandatory fields in requests :
router.post('/relations', controlBodyMiddleware(['userIdReceiver']), relation.create);
While you can have method like this :
controlQueryMiddleware(fields) {
return function(req, res, next){
if (!req.body.mandatoryField || req.body.mandatoryField !== 5){
return next(new Error('I want mandatoryField equal to 5'));
}
req.body.myFieldAccessibleInNextMiddleware = 'Yes, this would be there';
next();
};
}
I have found the solution myself.
It was all related to call back functions and passing the function definition to another function.
var app={
get:function(callback){
callback('Request object..','Response object..');
}
};
app.get(function(rq,rs){
console.log(rq,rs);
});
Here we can pass function definition in get method with parameters of your own choice that's what I wanted to know.
It is not necessarily express object or methods.
app can be any object and get can be any method of app.
With of course parameters not necessarily req and res objects.
while reading the node-mysql documantation i saw a usage as i pasted below
var query = connection.query('SELECT * FROM posts');
query
.on('error', function(err) {
// Handle error, an 'end' event will be emitted after this as well
})
.on('fields', function(fields) {
// the field packets for the rows to follow
})
.on('result', function(row) {
// Pausing the connnection is useful if your processing involves I/O
connection.pause();
processRow(row, function() {
connection.resume();
});
})
.on('end', function() {
// all rows have been received
});
i wonder how they use this events those can be used with the name whatever
user names the query query in example when i create custom events i name them first for example var foo=new events.EventEmitter and after this in whole page i have to use it as foo.on("someEvent")
but here they somehow bind the var created by user as event name in example code user names the mysql query as query and the event emitter has the same name somehow
and second question how is that possible to chain events as they use
.on("event").on("anotherEvent")
this question may sound strange but i really wonder how this works and it will change my code design completely
query is just your variable name for what is an instance of a Query in the node-mysql lib. You get access to all the functions that object exports.
on is inherited from EventEmitter in the node.js core. The key thing is that calling on returns "itself" i.e. this:
Returns emitter, so calls can be chained.
This allows you to chain calls to on
I have a namespace object on which I have defined some functions. One of the functions is used to create a websocket session to a remote server.
ns.Session = function(url, config, callback){
var ws = new WebSocket(url);
ws.onmessage = function (e){
if(login(e.data)){
// This is the point at which I need to pass back the session object to callback
callback(session):
}
}
....
}
In Javascript, as far as I know if someone invokes this function using ns.Session(....) then the this object will be ns. So, how do I get the instance of the "session" to send to the callback.
arguments.callee is deprecated as far as I know.
The whole reason I am doing it this way is that the session is not considered "usable" till the server confirms the login, so I don't want to prematurely return the function object before it is actually connected and logged in. Hence the use of a callback. If there is a better way to achieve this, I am open to that too.
Session has a bunch of other inner functions like addHandler, sendData etc which I have not shown here for sake of brevity.
You can use pointer to function like this:
ns.Session = function session(...) {
// 'session' here points to your function, so you do
callback(session); // like you wrote
callback(ns.Session); // same effect if you don't change ns and ns.Session pointers
}
Also, I don't see why you use the word "instance" in this case, because functions have only one instance. If you call it with the 'new' keyword, function creates new object from the function, and now there you can use "instance" word.