I am starting with nodejs and read basics on callback, here i have a code,
exports.handler = (event, context, callback) => {
var bx = require('barcode-js');
// Set default values.
var params = {
input: './1.bmp',
type: 'qrcode'
};
bx.analyze(params, function (err, results) {
if (err) {
callback('There was an error processing this image: ' + err)
}
results.forEach(function(result) {
callback(null,'Result type :' + result.type + '\t'+'Value: '+result.value);
});
});
};
what is happening bx.analyze(params, function (err, results) { in this line. why can't we just use bx.analyze(params) ?
The second parameter is function. Called a callback.
When you execute an async function, you can't wait for its returned value:
var result = bx.analyze(params); //you can't do this
So you tell the function that when it finishes its job, just call the callback (the function you passed as second parameter).
//so `analyze()` will call your passed function rather than `return` the result
//`err` will contain the error object if anything wrong happened in the analyze() function
//`results` will contain result if everything was fine
bx.analyze(params, function (err, results) {
if (err)
callback('There was an error processing this image: ' + err)
});
I strongly recommend you to learn how async code works in javascript. You can't learn Nodejs untill then..
Update:
In your code, the function handler is an async function so it takes a callback as a parameter (Just like analyze()).
When this function done with its job, it calls the callback.
Now in your code, it is called 2 times:
1) When an error occured, this function will call the callback and pass the error into it:
if (err) {
callback('There was an error processing this image: ' + err); //its passing "err" returned from analyze()
}
2) When everything goes well, it passes result set:
callback(null, 'Result type :' + result.type + '\t'+'Value: '+result.value); //the 1st parameter is being passed as "null" because there is no error in it, and second parameter passes the result
This is callback function which make the code asynchronous.
Means you are passing a function as argument to your bx.analyze(params) method. This callback method is executed once your bx.analyze(params) is finished, so its not blocking the other code, making the code asynchronous.
If you need how this call back is executed , then you have to look for Event loop, search it in Google,have lots of documentation.
if we use bx.analyze(params) then it is blocking (synchronous) code. event loop stop until bx.analyze(params) did not return any value and
there is no error handling.
if we use bx.analyze(params, function (err, results) { }); then it is asynchronous (non-blocking) code. event loop will not wait for returning value it goes to next statement and when bx.analyze(params, function (err, results) { return the callback event loop process it.
There is error handlation is also done
for deep understanding see this video https://www.youtube.com/watch?v=8aGhZQkoFbQ
Related
So I've been trying to set a global variable from inside a request, but seem to be getting nothing. The code I'm using
A username for testing is test2 after username=
var forSearching = "test2";
var name = "";
console.log(forSearching);
request("http://mercsystem.esy.es/get.php?username=" + forSearching, function(err, res, body)
{
if (err) return console.error(err);
var main = JSON.parse(body);
if (main.success == "false")
{
message.reply("Sorry, invalid user!")
}
else
{
name = main.Username
}
});
If you insert a console.log(name) right after you set the value, you will see that the value is set just fine.
The issue is likely one of timing. request() is an asynchronous operation. That means calling request() starts the asynchronous operation, then the rest of your code continues to run to completion and then, some time LATER, the callback gets called with the final asynchronous results.
Though you don't show where you are trying to use the name variable, you are probably checking the value of this global variable before the callback has been called and thus before the value has been set.
In node.js, what you are doing is not how you use asynchronous results. It will never work reliably (or at all). Instead, the only place to use your asynchronous result is in the callback itself or in some function you call from the callback and pass the result to.
var forSearching = "test2";
console.log("begin");
request("http://mercsystem.esy.es/get.php?username=" + forSearching, function (err, res, body) {
console.log("in request() callback");
if (err) return console.error(err);
var main = JSON.parse(body);
if (main.success == "false") {
message.reply("Sorry, invalid user!")
} else {
var name = main.Username
console.log(name); // value shows fine here
// use the name variable here or call some function and pass
// the name variable to it
}
});
console.log("after request() call");
// You cannot use the name value here (even if it was in a global) because
// the async callback has not yet been called
If you ran this code with the console.log() statement I've added, you would see this sequence of events:
begin
after request() call
in request() callback
From this sequence, you can see that code after your request() call runs BEFORE the async callback runs. Thus, you cannot use your name variable there, even if it is in a global.
I'm writing a notifier for 3 deal of the day websites in node. I go and parse the body of the webpage to grab the details. In the details there is a timer for the how long the deal will last. I'm reading that timer and trying to use setTimeout/setInterval to set when the function should execute again. However the function calls are continuous instead of waiting.
Pseudo code of what I'm doing:
var getData = function(url) {
request(url, function(err, resp, body){
if(err) throw err;
//process the body getting the deal information and timer
setTimeout(getData(url),timer*1000);
}
getData(url1);
getData(url2);
getData(url3);
Full code here.
I want the program to run, continually calling itself with the new timeouts for the webpages.
I'm a Node.js newbie so I'm guessing I'm getting tripped up with the async nature of things.
Any help is greatly appreciated.
EDIT:
more simply :
var hello = function(){
console.log("hello");
setTimeout(hello(),25000);
}
hello();
prints out hello continuously instead of hello every 2.5s. What am I doing wrong?
The problem is evident in your hello example, so lets take a look at that:
var hello = function(){
console.log("hello");
setTimeout(hello(),25000);
}
hello();
In particular this line: setTimeout(hello(),25000);. Perhaps you are expecting that to call hello after a 25 second timeout? Well it doesn't, it calls hello immediately, (that's what hello() does in Javascript, and there is nothing special about setTimeout), and then it passes the return value of hello() to setTimeout, which would only make sense if hello() returned another function. Since hello recursively calls itself unconditionally, it doesn't ever return, and setTimeout will never be called. It's similar to doing the following:
function hello() {
return doSomething(hello());
}
Is it clear why doSomething will never be called?
If you want to pass a function to setTimeout, just pass the function itself, don't call it and pass the return value: setTimeout(hello, 25000);.
Your fixed code:
var getData = function(url) {
request(url, function(err, resp, body){
if(err) throw err;
//process the body getting the deal information and timer
setTimeout(getData, timer*1000, url);
});
};
getData(url1);
getData(url2);
getData(url3);
Noticed that I passed the argument for getData as a third argument to setTimeout.
What's happening is 'request' is being run as soon as getData is called. Do you want getData to be the function you call to start the timer, or the one that loads the data?
var getData = function(url) {
function doRequest(url) {
request(url, function(err, resp, body) {
if(err) throw err;
//process the body getting the deal information and timer
}
setTimeout(doRequest(url),timer*1000);
}
getData(url1);
getData(url2);
getData(url3);
What you want is 'setTimeout' to point to a function (or anonymous function/callback) that you run after the timer expires. As you originally wrote, getData was immediately calling request (and then calling getData again after your timer)
I'm trying to learn how to use NodeUnit to test my NodeJs code. Ive written the following code, however each time I run the test, the result is OK: 0 assertions, no matter whether the input parameter is valid or not. Can anyone explain why this doesn't work and how I can fix it?
auth.class.js: This function accepts a user ID and returns a username.
exports.username = function(uid, callback) {
db.query('SELECT username FROM ul_logins WHERE id=?', uid, function(err, results){
if (err) throw new Error(err);
if(results.length > 0)
{
callback(null, results[0].username);
}
else
throw new Error("No results.");
});
};
authtest.js: This test will run successful every time, no matter what the uid is, and count 0 assertions.
var auth = require('./auth.class.js');
exports['username'] = function (test) {
auth.username(1, function(err, data){
return test.equal(data, "joe#example.com");
});
test.done();
};
The function you are testing is asynchronous (see the rewritten function below). You need to put the test.done() in the callback function:
exports['username'] = function (test) {
test.expect(2);
auth.username(1, function (err, data) {
test.ifError(err);
test.equal(data, 'joe#example.com');
test.done();
});
};
In your version, test.done gets called before the callback to auth.username is called. Use test.expect to tell nodeunit how many asserts it should receive before test.done is called.
You have a serious problem in your auth.username function. You should not throw in asynchronous code since a try-catch cannot be used to catch the error, leading to uncaught exceptions. You should always pass errors in asynchronous code to a callback as the first argument (convention). Your function should look like:
exports.username = function (uid, callback) {
var query = 'SELECT username FROM ul_logins WHERE id=?';
db.query(query, uid, function (err, results) {
if (err) {
return callback(err);
}
if (results.length === 0) {
return callback(new Error('No user found.'));
}
callback(null, results[0].username);
});
};
Note that errors are handled first (keeps the code neat), and callback calls in the branches are returned to avoid calling the callback multiple times (using else adds a level of indentation).
I get the impression that you are new to Node, and I remember having difficulty over this point too. Consider any function that does something over the network as asynchronous. This could take a long time, so to avoid blocking the process Node gets the OS to handle the task, and takes a callback to call at some point in the future when the OS gives it a result. This is why Node relies so heavily on callbacks. It leaves the Node process free to do other things (like call test.done in your question) while it waits. It also means that try-catch (which can only catch errors thrown in the same 'tick') no longer works. The conventional way to handle errors is to call the callback with the error as the first argument. All other arguments are for actual results.
I'm working with the parallel function in Async.js and for some reason the final call back is not getting executed and I do not see an error happening anywhere.
I'm dynamically creating an array of functions that are passed to the parallel call as such:
// 'theFiles' is an array of files I'm working with in a code-generator style type of scenario
var callItems = [];
theFiles.forEach(function(currentFile) {
var genFileFunc = generateFileFunc(destDir + "/" + currentFile, packageName, appName);
callItems.push(genFileFunc(function(err, results) {
if(err) {
console.error("*** ERROR ***" + err);
} else {
console.log("Done: " + results);
}
}));
});
async.parallel(callItems, function(err, results) {
console.log(err);
console.log(results);
if(err) {
console.error("**** ERROR ****");
} else {
console.log("***** ALL ITEMS HAVE BEEN CALLED WITHOUT ERROR ****");
}
});
Then in an outside function (outside of the function that is executing the forEach above) I have the generateFileFunc() function.
// Function that returns a function that works with a file (modifies it/etc).
function generateFileFunc(file, packageName, appName) {
return function(callback) {
generateFile(file, packageName, appName, callback);
}
}
I've looked at this SO post and it helped me get to where I'm at. However the final call back is not being executed. All of the items in the parallel call are being executed though. Inside of gnerateFile (function) at the very bottom I call the callback, so thats golden.
Anyone have any idea why this might not be executing properly?
The end result is to work with each function call in parallel and then be notified when I'm done so I can continue executing some other instructions.
Thanks!
Analyze what is happening line by line, starting with this:
var genFileFunc = generateFileFunc(...);
Since your function generateFileFunc returns function, so variable genFileFunc is a following function
genFileFunc === function(callback) {
generateFile( ... );
};
Now it is clear that this function returns nothing ( there is no return statement ). And obviously by nothing I understand JavaScript's built-in undefined constant. In particular you have
genFileFunc(function(err, results) { ... } ) === undefined
which is the result of calling it. Therefore you push undefined to callItems. No wonder it does not work.
It is hard to tell how to fix this without knowing what generateFile exactly does, but I'll try it anyway. Try simply doing this:
callItems.push(genFileFunc);
because you have to push function to callItems, not the result of the function, which is undefined.
Curious.
Best guess so far: Inside generateFile, RETURN callback instead of calling it.
You can achieve the stated goal with
async.map(theFiles, function(file, done) {
generateFile(destDir + "/" + file, packageName, appName, done);
}, function(err, res) {
// do something with the error/results
});
I'm using the node-soap client from milewise (create API by the way), but I have some difficulties to get the results of the callback to the right scope.
Here is the code I have for now:
function generateSoapRequest(req, res, next)
{
soap.createClient('http://127.0.0.1:' + cfg.service_port + cfg.service_url_path,
function(err, client) {
client.CXIf.CXIf.CXProcessXML(
{"XMLRequestData": {"CXLogon": {"UserID":"1901007", "Password":"2580", "LogonType":11 } } },
function(err, result, body) {
if (err) {
console.log(err);
return;
}
console.log(result);
var cxresponse = result.XMLResponse[0].CXResponse;
console.log('SessionID:' + cxresponse.SessionID + ' SessionInstanceID:' + cxresponse.SessionInstanceID);
});
});
}
function getVoiceMailInformation(req, res, next) {
var cxresponse = generateSoapRequest(req, res, next);
var something = doSomethingNext(cxresponse);
}
function doSomethingNext(cxresponse){....; return something;}
Basically, when I launch the getVoiceMailInformation(), it creates a soap client and request some information through the generateSoapRequest().
The next step would be to get the result of that function (not implemented in the code above, because I don't know how) and do something else.
My problem is soap.createClient is asynchronous, so the callback is fired well after the function is complete.
What would be the best approach ?
(Maybe it's something trivial, but the scope of an anonymous function in javascript is something that is killing me.)
Any help will be very appreciated.
Basically you can't do something like:
var cxresponse = generateSoapRequest(req, res, next);
because the function you're calling invokes asynchronous code, and therefore can't return a value that's determined by that code. The normal way around this is to give the function an extra callback parameter for a function that will be called with the result once the result becomes available. It doesn't have to be an anonymous function; it can be a named function. In your case, (assuming you've modified generateSoapRequest to take a callback as its fourth argument and call it when the results are ready, you could write
generateSoapRequest(req, res, next, doSomethingNext);
and then doSomethingNext will be called with cxresponse as an argument. Of course, since doSomethingNext also gets called asynchronously, it can't return a value either, so you'll have to apply the same technique to it.
The async module can make this sort of thing easier: in particular, its "waterfall" pattern is useful when you have a bunch of functions that have to run in sequence, each being called back from the previous one.