My questions here is about the way the call back function works.
const fs = require('fs');
let fileContents = 'initial value';
fs.readFile('file.txt', 'utf-8',function(error,res){
fileContents = res;
console.log(fileContents);
})
So, when the fs.readFile runs, the function(error,res) is called. But why does the fileContents receives the text inside the txt file if my parameter is empty?
I'm assuming that the readFile adds the value read to the res parameter.
Is it always like this?
Another questions is why do I get null when I erase error?
Readfile looks like something like this:
function readFile(path, cb) {
try {
// Some very complicated stuff
// All fine, call callback:
path(/*error:*/ null, /*res: */ "somedata");
} catch(error) {
path(error, /*res: */ undefined);
}
}
So what you get inside the callbacks parameter does not depend on its name, but on its position, so when you do:
readFile("/..", function(res) { /*...*/ });
res will be the error readFile passes back, and if thats null its a good thing.
Maybe take a little time to experiment with callback functions.
A callback function is just a function that you pass as a parameter to another function. In the code below I declared my function. myFunc uses another function as parameter to the function called callback. Inside my function I invoke the function and pass myName as parameter to the callback. This allows me to declare other anonymous functions as parameters which I included as examples. When myFunc is invoked it invokes the callback inside its local environment.
I can then manipulate the data that is passed to the callback and write my own code inside the anonymous function using the variable that is passed to myFuncs callback.
In your example you are using readFile which retrieves the data from the file and passes it to a callback function and/or passes an error assuming something went wrong.
function myFunc( callback){
let myName = "Joe Smo";
callback(myName);
}
/*
Now I can use my function and add another anonymous function to do whatever I want
provided I use the same parameters that are inside my function.
*/
myFunc(function(name){
console.log("What's up!"+name);
});
myFunc(function(strangeName){
console.log(strangeName+" is a strange name.");
});
Related
Sorry for the ambiguous title, I just didn't know what else to put. Im learning JS and in the video the person does this.
When he calls the addListAfterKeyPress method at the bottom, why does the function call work? I thought he would have to put in a argument for the addListAfterKeyPress to take in since it has an event parameter. But in the end the code works perfectly. And also, when can i call a function that takes a parameter without explicitly passing one like how he did it in the picture?
This is a so called callback.
addListAfterKeypress at line 30 is not a call to this function, it is just saying, whenever the event keypress is raised on this input element, call this function.
Who is calling the function is the DOM library, indeed. You just have to pass a pointer to the function to be called.
Even more, the addListAfterKeypress function expects an event parameter, which will be provided to the function by the DOM library.
I think it is a bit more understanding by looking at an annonymous function there.
input.addEventListener('keypress', event => {
// This will be run whenever the input raises an event of type 'keypress'
// Here, the DOM library provides me an event parameter
});
Edit on demand:
Be aware, I am using ES6 just for comfort.
Suppose having this function
const callback = () => {
console.log(`My callback function is being executed`);
};
I will be using setTimeout to mock the HTML events. setTimeout is a function that expects a callback to execute after n milliseconds.The first parameter is the callback itself, the second is the amount of milliseconds, n.
See https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(callback, 500); // After 500ms, function callback will be fired
Here, I am just passing a pointer to the setTimeout function. This pointer must point to a function that will be called by setTimeout.
Let's write our own function that takes a callback as a parameter.
const callback2 = (number) => {
console.log('I received this parameter', number);
};
const callbackWrap = (callback, n) => {
// Here, callback parameter is a function that I can invoke, actually
console.log('The wrapper will execute the function passed as parameter');
callback(n);
};
Now, we can call the wrapper pointing to the new callback (callback2).
callbackWrap(callback2, 3);
callbackWrap(callback2, 4);
Or, we can define our function directly on the parameter list.
That is, we are passing an annonymous function
// p is the parameter of the callback function
callbackWrap(p => {
// Since callbackWrap will call the function parameter
// by passing a single parameter,
// the function I am declaring, expects that parameter
console.log(`Received ${p} inside the annonymous function`);
}, 'Parameter');
So, to summerize a bit, just the same way you can declare a variable (let's say, of type number) and then pass it to a function as a parameter, you can declare a function to pass it the same way.
const normalParameter = 30;
const functionParameter = p => console.log('Another callback', p);
callbackWrap(functionParameter, normalParameter);
// Or maybe passing more complex parameters
const anotherParameter = [1, '2', {3: 4}];
callbackWrap(functionParameter, anotherParameter );
Hope it clarifies a bit.
I have this piece of code below:
It makes a GET call to an URL, gets some object, and appends an image to an HTML tag.
function getDataFromApi(searchTerm, callback) {
const URL1 = `some url`;
const design = {
url: URL1,
data: {
"dog breed name": searchTerm
},
type: 'GET',
success: callback
};
$.ajax(design);
}
function displaySearchData(data) {
const allResultsLength = data.message.length;
const ranNum = Math.floor(Math.random() * allResultsLength);
const dogResults = data.message[ranNum];
$(`.js-search-results`).html(`<img src = ${dogResults}>`);
}
function watchSubmit() {
$('.js-search-form').submit(event => {
event.preventDefault();
let queryTarget = $(event.currentTarget).find('.js-query');
let query = queryTarget.val();
queryTarget.val("");
getDataFromApi(query, displaySearchData);
});
}
$(watchSubmit);
I get the getDataFromApi and watchSubmit but getDataFromApi(query, displaySearchData); isn't intuitive to me at all.
I've been writing Java, and it doesn't make sense to me how displaySearchData is getting called without the parameter - it seems that line should be getDataFromApi(query, displaySearchData(data));.
Can someone please explain how this is getting compiled & executed (basically how this is a legitimate syntax) in javascript?
Somewhere in the good'ol jquery, there lies this piece of code:
$.ajax = function(config){
...
// get the response from XHR request,
// and save it in, say, 'response'
...
// now check, if the response is OK 200
// and if so, execute next line
// which is basically - calling your displaySearchData method
config.success(response);
...
}
now, config is your design object, which has a property success which carries the reference to your displaySearchData method.
The data argument of method displaySearchData will now carry the reference to variable response passed in the method invocation config.success(response).
EDIT: the argument callback also carries forward the reference of the method displaySearchData to getDataFromApi
Concept to be noted:
functions can be passed in Javascript as arguments to another function, in which case we only need the referring variable to be passed as argument. Invocation parentheses () are not required.
function A(data){...};
function b(referenceToFunctionA){
...
referenceToFunctionA(someData);
...
};
// correct
b(A);
// wrong, because adding () after any function reference variable
// invokes the method immediately.
// in this particular case the returned value of the method A
// is passed as argument instead of the reference to method A itself.
b(A());
Welcome to JavaScript My Friend. Get ready to experience more magical weirdness as you continue to work on JS. Good luck.
What you need to look at is in the function getDataFromApi().
In that function, you have a "callback" parameter. This parameter is later added into $.ajax. This is a jQuery function that will provide some callback when a certain condition is matched (like before sending a request, when the response has been received,...). This $.ajax callback provide you with 3 parameters, one of them is data (which are being used, textStatus, and jqXHR. Usually, you only need to pay attention to the data since it contains the response from where you are requesting data.
So when the $.ajax success, the "callback" function will be called, which is the displaySearchData. And since $.ajax callback provides you with the data parameter, you can add them to the parameters of displaySearchData. Do note that you can add the extra 2 provided parameters if needed.
You can have a look at that function here: jQuery Ajax
Playing around with the .on('click', ) event and I get differing behaviour based on whether I supply an anonymous vs named function (the named function doesn't work). Is this a syntax error?
<div id="myID"> abc </div>
<script>
$("#myID").on('click',function(e){
console.log(e.type);
}); //works
function handle(e){
console.log(e.type);
}
$("#myID").on('click',handle(e)); //doesn't work
</script>
You need to replace
$("#myID").on('click',handle(e));
with
$("#myID").on('click',handle);
When you call a function, it is executed immediately. This happens when you do
$("#myID").on('click',handle(e));
You call the function, passing an event e which does not exist yet. What you want instead is giving jQuery a function that it should call when the user clicks on the element with the id myID.
This is possible in JavaScript because it has first-class functions. This means that if you create a function like this:
function handle(e){
console.log(e.type);
}
then you get a reference to the function that you just created. This reference is stored in a variable named handle. You could achieve the same if you do:
var handle = function (e) { // create a function and store a reference to it in a variable
console.log(e.type);
};
The function takes an argument e. This doesn't exist yet, it has to exist in the moment you call the function:
handle(e); // ReferenceError: e is not defined
You can pass the reference to that function to jQuery, which then calls your function when the user clicks the element. At that point, e still doesn't exist, because it will contain information about the event, which hasn't occured yet. It will look like this:
$("#myID").on('click', handle); // pass a reference to the handle function to jQuery
Now, handle doesn't get called, because you only pass a reference to the function. You could say that you pass the function as an argument to another (jQuery) function. This is called a callback function.
Edit
Note that all functions that were created above take e as their argument. The argument doesn't have to exist in the very moment you create the function. However, when you (or jQuery) call the function, you have to provide an argument so that the function can do its job.
It's the same with an unnamed function: you create the function, but the argument does not exist yet. When you (or jQuery) call the function, you have to provide an argument.
This means there is no essential difference. The only difference is that one function has a name, the other one doesn't. You could even do this:
$("#myID").on('click', function handle (e) { // pass a reference to the function, but do not call it
console.log(e.type);
});
... which has the same effect as:
$("#myID").on('click', function (e) { // pass a reference to the function, but do not call it
console.log(e.type);
});
... except that in the first example, you keep a reference to the function that you created in a variable called "handle". In the second example, you lose the reference to the function, and only jQuery will be able to use your function.
Edit end
Another example for that would be:
var testFunction = function (arg) {
console.log('My argument is:', arg);
};
var executeTwoTimes = function (callback) { // accept a callback function as the first argument
callback('foo'); // execute the callback function
callback('foo');
};
executeTwoTimes(testFunction); // pass a reference to testFunction
// or:
executeTwoTimes(function (a) { // pass a reference to an anonymous function
console.log(a + ' bar');
});
I hope I could make things clearer for you.
How does the callback in fs.readfile get called when using fs.readfile.bind(context,pathArgument) like so. //understandable because my task function knows the name of the callback parameter
async.series([function(callback){
//operation done callback()},...],finalCallback(err,result));
BUT
//not understandable
async.series([fs.someOperation.bind(null,firstArgument),...],finalCallback(err,esult))
I believe I understand partial application;however, it would look something like this. function(callback){ fs.someOperation(firstArgument, ????)}(asyncCallbackFunc) and then I have no idea how the second argument is called...
Thx, in advance for helping me clear this up.
All bind does is set the context of the callback. It is still a regular callback like any other. Except, it is explicitly told what this will be. Looks like in your case, it is set to null.
The bind function on function object allows you to set the context i.e the value of this inside the function body as well as allow you to create a partial function in case you pass some arguments while calling bind.
For example:
function add(a,b) {
console.log(this);
return a+b;
}
var newAdd = add.bind("hello world", 10);
The newAdd will be one argument function which gets added to 10 and the result is returned. Also when newAdd is called the "hello world" will be logged in console.
Now when your code says fs.readFile.bind(null, path) it means that the return function will be of one argument which is the callback for readfile i.e the return function will be of form function(callback) { ... } which is exactly what is required to be passed to async.series
The main idea in the code you posted is to create a partial function that accepts only callback so that it can be passed to async.series the null argument doesn't play any role but you need to pass a context argument to call bind function, hence a null is passed as context arg.
I am trying to understand a code from socket.io/examples/chat/app.js.
I am not able to explain what the fn() calls mean in the lines 71 and 73.
I guess it is a callback function but where is its definition?
Is it a short invocation of another function from app.js ?...
Is it a call of a prototype function of the socket object?
The fragment is (lines 69-78):
[...]
socket.on('nickname', function (nick, fn) {
if (nicknames[nick]) {
fn(true);
} else {
fn(false);
nicknames[nick] = socket.nickname = nick;
socket.broadcast.emit('announcement', nick + ' connected');
io.sockets.emit('nicknames', nicknames);
}
});
[...]
fn is passed in as an argument to the callback function, right here:
socket.on('nickname', function (nick, fn) {
^^
Since JavaScript functions are objects, they can stored in variables — and passed as arguments into other functions.
The use of the callback function in this particular case is duscussed in the “Getting acknowledgements” section of the Socket.IO docs — calling it with some data sends a message back to the client as a response to that message.
fn is a reference to another function that is being called from within the on nickname event.
IN javascript, functions are treated as objects so they can pass as an argument with in a callback function.