Hi I am trying to execute a callback in a if statement but I get "TypeError: callback is not a function"
This is my code:
socket.on('authenticate', function (data, callback) {
// this works
callback("false");
// this doesn't work
if (data == "abc") {
callback("true");
}
});
Always check if callable function is passed, at least just do if(callback)
in Your problem there may be situation that clientside not waiting for callback (done emit call without passing callback argument).
Try this solution:
socket.on('authenticate', function (data, callback) {
console.debug('socket authenticate:', data); // for debug purposes
if (data == "abc") {
if(callback) { // callback may not be passed
callback(null, true); // keep in mind in callbacks first argument is error second is result
}
return; // return will prevent execution to go down, because most of times used for resulting call.
}
if(callback) { // callback may not be passed
callback("Not authenticated", false);
}
});
Related
i have a situation where my asynchronus nodejs method from a third party library is taking too long. i want to set a timeout limit on this call and if it does not return within that timeout, i want a callback to happen with default(empty) values.
current code
wrapperfunct(data, function(value, err) {
//do everything with value or err
})
wrapperfunc(data, callback) {
thirdpartylib.getData(input, callback)
}
i am noticing that getData sometimes hangs, that prevents the callback from happening. i want a behavior than if getData does not call the callback method in specified time, i call callback with default values, say (null, null).
You can make your own timeout like this:
wrapperfunc(obj, timeout, data, callback) {
var done = false;
var timer = setTimeout(function() {
done = true;
// callback with both values null to signify a timeout
callback(null, null);
}, timeout);
obj.thirdpartylib.getData(input, function(err, data) {
if (!done) {
clearTimeout(timer);
done = true;
callback(err, data);
}
})
}
Note: The value of this in your proposed function was probably not correct so I substituted obj. You will either have to pass that value in or you will have to use some variable that is within scope for that.
Where are people getting cb() from, is this a Node thing or vanilla JS thing?
For example:
Managing Node.js Callback Hell with Promises, Generators and Other Approaches
they're using cb() to I guess callback and return an error or a value or both in some cases depending on what the callback function sig is?
cb in the context you're describing it is how a vanilla callback function is passed into a (typically) asynchronous function, which is a common pattern in node.js (it's sometimes labelled next, but you can call it bananas if you so desire - it's just an argument).
Typically the first argument is an error object (often false - if all went as planned) and subsequent arguments are data of some form.
For example:
function myAsyncFunction(arg1, arg2, cb) {
// async things
cb(false, { data: 123 });
}
then using this function:
myAsyncFunction(10, 99, function onComplete(error, data) {
if (!error) {
// hooray, everything went as planned
} else {
// disaster - retry / respond with an error etc
}
});
Promises are an alternative to this design pattern where you would return a Promise object from myAsyncFunction
For example:
function myAsyncFunction2(arg1, arg2) {
return new Promise(function resolution(resolve, reject, {
// async things
resolve({ data: 123 });
});
}
then using this function:
myAsyncFunction2(10, 99)
.then(function onSuccess(data) {
// success - send a 200 code etc
})
.catch(function onError(error) {
// oh noes - 500
});
They're basically the same thing, just written slightly differently. Promises aren't supported especially widely in a native form, but if put through a transpiler (I'd recommend babel) during a build step they should perform reliably enough in a browser too.
Callbacks will always work in a browser with no shimming / transpilation.
node.js has lots of asynchronous operations that take a completion callback as an argument. This is very common in various node.js APIs.
The node.js convention for this callback is that the first argument passed to the callback is an error code. A falsey value for this first argument means that there is no error.
For example:
fs.readFile("test.txt", function(err, data) {
if (!err) {
console.log("file data is: " + data);
}
});
A function you create yourself may also define it's own callback in order to communicate the end of one or more asynchronous operations.
function getData(id, cb) {
var fname = "datafile-" + id + ".txt";
fs.readFile(fname, function(err, data) {
if (err) {
cb(err);
} else if (data.slice(0, 6) !== "Header"){
// proper header not found at beginning of file data
cb(new Error("Invalid header"));
} else {
cb(0, data);
}
});
}
// usage:
getData(29, function(err, data) {
if (!err) {
console.log(data);
}
});
From the Vanilla JS, you can declare a function and pass throuw parameters a declaration of another function, that can called async
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
Consider this code:
var async = require('async');
var a = function()
{
console.log("Hello ");
};
var b = function()
{
console.log("World");
};
async.series(
[
a,b
]
);
Output is
Hello
Why is World not part of the output?
The async.series function passes one callback to each of the methods that must be called before the next one is called. If you change your functions a and b to call the function it will work.
function a(done){
console.log('hello');
done(null, null); // err, value
}
function b(done){
console.log('world');
done(null, null); // err, value
}
For each method called in series it is passed a callback method which must be run, which you are ignoring in your example.
The docs say:
tasks - An array or object containing functions to run, each function
is passed a callback(err, result) it must call on completion with an
error err (which can be null) and an optional result value.
The reason why your code is stopping after the first method is that the callback isn't being run, and series assumed an error occurred and stopped running.
To fix this, you have to rewrite each method along these lines:
var b = function(callback)
{
console.log("World");
callback(null, null) // error, errorValue
};
It's possible I don't understand Node's event loop well enough.
Say I have a function foo which contains an asynchronous function async_func. Do I have
//1
function foo(callback) {
//stuff here
async_func(function() {
//do something
callback();
});
//this eventually get executed
}
or
//2
function foo(callback) {
//stuff here
async_func(function() {
//do something
return callback();
});
//never executed
}
Actually, in your sample 2, //never executed will be execute every time. It's returning from the callback, not from the wrapping function.
Sometimes the caller actually expects some return value and the behavior can change based on that. Another common reason to see a return callback() is just a clear way of short circuiting the function you're in. For example.
function doSomething(callback) {
something(function(err, data) {
if(err) return callback(err);
// Only run if no error
});
// Always run
}
Even though the return value isn't being used, it's using return to ensure that execution doesn't continue past the error conditional. You could just as easily write it this way which has the same effect.
function doSomething(callback) {
something(function(err, data) {
if(err) {
callback(err);
return;
}
// Only run if no error
});
// Always run
}
If I have the following code:
var content;
var f = fs.readFile('./index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
return console.log(content);
});
f();
I got the following:
f();
^
TypeError: undefined is not a function
How can I do to return a function, which is not undefined?
My real issue, in a bigger context is the following https://gist.github.com/jrm2k6/5962230
You can't usefully return from within the callback to your code.
Using return inside the callback doesn't return a value to your code. fs.readFile() calls the callback itself so the return value is given to it. For your code to receive it, fs.readFile() would have to return the value it got from the callback, which it doesn't.
And, since fs.readFile() is asynchronous, it actually can't. Your code spans 2 different points in time:
"Present"
var content;
var f = fs.readFile('./index.html', /* ... */);
f();
"Future"
/* ... */
function read(err, data) {
if (err) {
throw err;
}
content = data;
return console.log(content);
}
/* ... */
You simply can't use a value from the "Future" in the "Present" -- or, at that point, the "Past."
This all generally leads to continuing the callback pattern rather than using return. Taking your "real" code:
var cheerioURLContent = function (url, callback) {
rest.get(url).on("complete", function (result) {
callback(cheerio.load(result));
});
};
cheerioURLContent('./index.html', function (t) {
console.log(t);
});
You can assign event handlers for custom events and trigger (emit) the events from within the callback. It's a bit hard to get your head around at first, but pretty elegant.
See Emitting event in Node.js for an example.