I am using the node request module which is setup as follows:
request(object,function(data));
The function is a callback with the response data in it. I want to feed in a predefined set of objects, and wrap the request function in another function like so:
var quickReq(object,func){
request(object,func);
}
quickReq({
"method":"GET",
"url":"http://someapi.com",
}
,function(error, response, data) {
res.send(data);
});
Is this valid async code?
Is this valid async code?
Yes, yes it is.
It's not at all clear what you're trying to do, but the first parameter to request's callback is an error code, and the second parameter is the returned content (assuming it succeeded).
Related
I'm using request to call an API which gives me movies data in an object called body, but when I try to pass it to an array and console log it, the terminal shows me an empty array.
let copy = [];
const request = require('request');
request('https://www.omdbapi.com/?t=JOKER&apikey=b04f2804', { json: true }, (err, res, body) => {
if (err) { return console.log(err);}
copy.push(JSON.parse(JSON.stringify(body)))
});
console.log(copy);
First off, the request() library is deprecated and it is not recommended that you write new code with it. There is a list of alternatives (that all support promises) here.
Then second, the request() library is non-blocking and asynchronous. That means that when you call request(), it starts the operation and then immediately returns. The code after the call to request() then continues to execute BEFORE request() calls its callback. So, you're trying to examine the array before its value has been set. This is a classic issue in asynchronous programming. There are a number of ways to handle this. If you stayed with the request() library, then you must either use the result INSIDE the callback itself or you can call some other function from within that callback and pass it the array.
With one of the listed alternatives that all support promises (my favorite is the got() library), you can then use await which is often a preferred programming style for asynchronous operations:
const got = require('got');
async function someFunction() {
let result = await got('https://www.omdbapi.com/?t=JOKER&apikey=b04f2804').json();
// you can use the result here
console.log(result);
// Or you can return it and it will become the resolved value
// of the promise this async function returns
return result;
}
someFunction().then(result => {
// can use result here
}).catch(err => {
console.log(err);
});
Note that when you are writing asynchronously retrieved data to a higher scoped variable as you are when you do copy.push(), that is typically a warning that you're doing something wrong. This is because NONE of the code in the higher scope will know when the data is available in that variable. There are rare cases when you might do that (like for implementing a cache), but these have to be situations where the data is being stored only for future reference, not for immediate use. 99.9% of the time when we see that construct, it's a wrong way to program with asynchronously retrieved data.
I am using https://github.com/request/request.
The example that is given is:
const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
How can I use body elsewhere in my code? I want something like return body but nothing works. I can't use it anywhere!
You cannot directly return an asynchronous result from outside the request() callback. This is not unique to this particular function, but is how all asynchronous callbacks work in Javascript.
When you call request() it starts an asynchronous operation and turns it over to native code. The JS interpreter then goes about it's merry way executing the rest of your Javscript after this function call (not in the callback, but after that). So, you should be able to immediately see that the body result does not exist yet, but the rest of your Javascript is already executing.
Then, some indeterminate time later (depending upon how responsive the server is that you're contacting and how big the result is), when the JS interpreter has nothing else to do, the callback gets called and the body result is available.
So, the ONLY place in your code that you know the body result is good and is available is INSIDE that callback. So, the general way of programming with an asynchronous operation like this in Javascript is that you use the result inside the callback. Any code that needs to use that result gets put inside that callback or you can put the code in a separate function and call that function from inside the callback and pass the body result as an argument to the function.
If you wanted to wrap this request in a function and communicate back that result to the caller (which is not exactly what you show here, but another way to write the code), I'd suggest you first read How do I return the response from an asynchronous call? because it outlines the various ways you can communicate back the body result from your asynchronous operation (another callback or use promises).
To many newbie Javascript developers this seems somewhat heretical. What do you mean I can't just call a function, get the result and return it from the function? Well, that's the extra complication with Javascripts non-blocking, asynchronous I/O model that is entirely event driven. Once you get down the learning curve, you will find a huge number of advantages in the language that flow from this architectural model, but you will have to deal with this extra complication.
The language is evolving to make this type of programming simpler with the use of promises in async functions and then the use of await to "wait" on a promise. If you use the request-promise library instead of the request library (request-promise is derived from request), then you can deal with a promise as the return value and you have more options.
const rp = require('request-promise');
async getMeSomeData() {
try {
let body = await rp('http://www.google.com');
console.log(body);
// can put code here that uses body
return body; // becomes the resolved value of the returned promise
} catch(err) {
console.log(err);
throw err; // makes sure the returned promise is rejected
}
});
getMeSomeData().then(body => {
// use the body here
}).catch(err => {
// error here
});
Note: I showed possibly using the body value or err inside getMeSomeData() or at the caller. Usually, you would do one or the other, but I wanted to show both ways.
I want to be access array outside the function or outside the loop in nodejs. I written following code.
var result = [];
function setid (swfid){
crud.getswift(swfid).then(function (response) {
console.log("response",response);
result = response;
// res.send(response);
}).catch(function (err) {
return ("error:" + err);
});
console.log("result",result);
}
console.log("result",result);
But its returning null. your suggestions please
You wrote a new statement in the function call and therefore you scoped it. This is one of the things wrong there. Apart from that, as the first person commenting to this answer mentioned, you have an async call here. Therefore, you need to return a promise from setid and wait for the response to get the result.
You're mixing your Aysnc logic with Sync. You won't get the response outside the .then function scope because there's no response available at the time you're trying to get the results.
Try using a callback in the promise - You'd need to invoke the function in the promise callback and send the response as function param, then play with the data.
> Promise / API call etc
.then(() => gotDataCallBack(data));
gotDataCallBack(data){
// handle your data and logic here.
// this will make sure you have the data available before you move ahead with
your application/manipulation logic.
}
I am reviewing a sample nodejs server code, which is working fine. but could not understand the following code:
var handlers = {};
// Creating a sample handler
handlers.sample = function(data,callback){
callback(406,{'name':'sample handler'}); // How is this line of code working??
};
// Creating a not found handler
handlers.notFound = function(data,callback){
callback(404); // How is this line of code working??
};
In the entire code there is no implementation of "callback" function then how
callback(406,{'name':'sample handler'});
and
callback(404);
are working?
Please suggest. Thanks.
callback isn't implemented in the code you posted; it's a named parameter.
To call one of the functions that requires a callback, you'll need to pass it in as an argument, like:
handlers.sample("some data", () => console.log("I'm in a callback!));
The first argument ("some data") goes in the data parameter, and the second argument (() => console.log("I'm in a callback!)) goes in the callback parameter. When callback(404) is run, it executes the callback function (in the above example, it would do console.log("I'm in a callback!)).
Basically, when you call handlers.sample, you should pass a function as your second argument, and that function will be called, usually asynchronously, and presumably after something is done with the data you pass as the first argument. For example, based on the code you provided:
handlers.sample(dataObject, (number, object) => {
console.log(number)
console.log(object.name)
})
would yield this result in the console:
406
sample handler
I’m curious if this is a public library you are seeing this code in, so we can take a closer look?
I did a further digging in into this and found that
selectedHandler
in the following code (this is not mentioned in the question) is getting resolved into handlers.sample or handlers.notFound variable names based on some logic (which is not mentioned here)
selectedHandler(data,function(status,payloadData){
// somelogic with the status and payloadData
});
And second parameter of this function which is a complete function in itself
function(status,payloadData){
// somelogic with the status and payloadData
}
is going as the second parameter in handlers.sample or handlers.notFound which is a Callback. So execution of Callback in the current context is execution of this function (this function is anonymous because it has no name and getting executed as Callback)
When I receive the 'catch' callback, 'this' is undefined, even using arrow funcitions. Any ideas?
private all(req: Request, res: Response): void {
EntityRepository.getRepositoty(req.params.etName).then(repo => {
...
}).catch((err) => {
this.handleError(res, err); // here I get undefined.
});
}
how the all func is called.
It's called based on a Express route.
Added mathod bind as #jfriend00 suggested.
constructor() {
// Connect to database.
DataAccess.connect();
// Starts configuring routes for api
this.router = Router();
// Bad request due to absence of entity type.
this.router.get("/", (req, res) => {
res.statusCode = 400;
res.statusMessage = SysMsgs.error.noEntityTypeSpecified.message;
res.send();
});
// Added method 'bind'.
this.router.get(this.routeBase, this.all.bind(this));
this.router.get(this.routeBase + "/:id", this.findOne.bind(this));
}
With arrow functions, this will retain the value it had in the scope prior to the arrow function call. In your case, that means it will have whatever value this was at the beginning of your all function. So, that value of this depends upon how the all function is called.
And, based on your this.router.get() where you specify this.all as the callback, that means that this inside of all will be set to whatever Express sets it to when it calls that callback. And, that is undefined.
You can fix your issue by using .bind().
this.router.get(this.routeBase, this.all.bind(this));
That will assure that the appropriate this is set when .all() runs. And, then your arrow function inside of all() will use that value of this.
Note: you will need to use .bind() for any method you are passing as a callback where you expect this to be the object inside the callback. When you pass something like this.all, the value of this is lost and only a reference to the method is passed. The caller then calls that method as a normal function with no object binding. You use .bind() to take control of that yourself. .bind() essentially creates a little stub function that reattaches the appropriate this pointer by calling your method using it.
You could also make your own wrapper arrow function for it:
this.router.get(this.routeBase, (req, res) => this.all(req, res));
which as Saravana points out will retain TypeScript type checking.
While #jfriend00's answer covers the problem with your code and there is nothing wrong with using bind in JavaScript, there is one little problem when you use bind in TypeScript though. The type signature for bind is:
bind(this: Function, thisArg: any, ...argArray: any[]): any;
Notice that bind returns any meaning any type checks on the returned function is turned off, which leads to subtle bugs. Take the following for example:
// Assume the definition for `router.get` is something similar to this:
get(routeBase: string, callback: (req: Request, resp: Response) => void)
// ... and in the place you are calling it
private all(param: number): void {
}
this.route.get(this.routeBase, this.all.bind(this));
// No compiler error, but `all` and the callback parameter expected by `route.get` don't match!
If you would like to keep type checking you can use something like below instead of bind:
this.route.get((req, resp) => this.all(req, resp));
See: https://github.com/Microsoft/TypeScript/issues/212