Optional paramters in Vanilla-javascript - javascript

I dont know how to make function arguments to be optional in a certain case.
The case is if I have at more than one argument and not the last one should be optional. I see the ejs templating engine solves this:
ejs.renderFile(templatesPath, options, (err, html) => {
if (err) {
console.log(err);
error = err;
} else {
res.write(html);
res.end();
}
})
So if I dont pass the options paramter, the callback function will still be recognized as a callback function and not as the options object - and the role, assigned to it, remains to be callback function and not the role of the missed paramter - as it would normally.
So how can it be solved - in Javascript - that I still define 2-3 or more arguments (in the function definition) but if I dont pass an optional one - which is not the last - that it doesnt change the passed paramters role.
Thanks

What matters is the order of the parameters. Therefore, you must repect it.
Just pass undefined, null or an empty object {} if the function does not support no value.
Below, options is declared but not valued (undefined). The order is respected, it will work.
You can keep this way: always declare variable to pass them to the function, and assign value to them only when you have it.
var options;
ejs.renderFile(templatesPath, options, (err, html) => {
if (err) {
console.log(err);
error = err;
} else {
res.write(html);
res.end();
}
});

Related

Wanted help in understanding how parameters are defined in Callback functions, using this example (if possible)

I am trying to understand more on how callback functions work in JavaScript.
I found this simple example code online and after adding the imports & additional txt file it's working. However I am not sure why it is working as the parameters of the functions aren't being defined anywhere?
fs.readFile(`${__dirname}/temp.txt`, (err, data) => {
console.log(`Breed: ${data}`);
superagent.get(`https://dog.ceo/api/breed/${data}/images/random`).end((err,res) =>{
console.log(res.body)
}); })
Upon running this I get the expected result on the console with the line displaying Breed: ${data} and the next line showing the body of the res.
However, the err, data parameters have never been provided to the arrow function within readFile. Neither has the err,res parameters ever been called/provided a value for it to display a message to the console, then how are these lines displaying a message to the console?
I could have understood this working if .readFile returned a err and data value & .end returned a err and res value, however upon reading the documentation both these functions return void, thus i'm confused and help would be appreciated.
You pass a function in to readFile, and later on readFile will call your function. When it calls your function, readFile will pass in the relevant values.
You can do something similar yourself, like this:
function myReadFile(filename, callback) {
setTimeout(() => {
if (Math.random() > 0.5) {
callback(null, 'fake file');
} else {
callback('an error', null);
}
}, 1000);
}
myReadFile(`${__dirname}/temp.txt`, (err, data) => {
console.log(`Breed: ${data}`);
})
(though of course the real readFile function isn't doing timeouts or random numbers, but rather reading from a file and listening for that operation to succeed or error out)

Reading a file - fileName is not defined [error]

I am completely new to JavaScript, and I am having a trouble with using fs.readFile() function.
I am required to read a file, and determine whether I have to call successFn (when err boolean is false) or errorFn (if err boolean is true).
When I err is false, however, I am trying to call an "extractor" function as a parameter -- extractor separates the data read into each word.
I am required to call fs.readFile, so I am required to use parameters and one of the parameters is fileName.
The grader is going to test my code using his own files, so I am not supposed to define fileName, yet I am being asked to define it (I understand why I am being asked to do it, but I feel that there should be a way to get around this issue.)
Also, JavaScript syntax is very not intuitive, so I might be making some mistakes with the syntax, but here is my code, and please let me know how I can fix my issue:
function readAndExtractWith(extractor) {
fs.readFile(fileName, 'utf-8', (err, data) => {
if (err) {
errorFn(err);
}
else {
data = extractor();
successFn(data);
}
return extractor;
});
}
fileName is not defined because you never define it. Since you are using that in a function you need to either pass the variable as an argument, specify it inside the function, or define it globally.
var fileName = "stackoverflow.jpg";
// when executing the function pass the fileName parameter
readAndExtractWith(extractor, fileName);
function readAndExtractWith(extractor, fileName) {
fs.readFile(fileName, 'utf-8', (err, data) => {
if (err) {
errorFn(err);
}
else {
data = extractor();
successFn(data);
}
return extractor;
});
}

How are callback functions' parameters dependent on ordering?

Let's say I have an event I'm waiting for in Javascript, where we'll have something like this:
fileSystem.readFile('done', function(err, data){
//do something with the file
});
In this situation, the parameters err and data are arbitrarily named and ordered, so they could have been in another order
function(data, err) {/*do something*/ }
How does data get passed the data and err get passed any errors?
I notice this pattern to be pervasive everywhere through out javascript callbacks, and it is largely a mystery to me how function parameters are passed in a predictable order without following some convention I must not be aware of.
How does this work?
What happens is that when you call
fileSystem.readFile('done', function(err, data){
//do something with the file
});
the function you pass as the second parameter will be saved for later use (when the file is finished reading). It will then call the function you passed for you, with a possible error value as the first parameter, and the file contents as the second parameter.
readFile = function(event, callback) {
var error = null;
var fileContents = /* read file implementation. Maybe error will be assigned some value here */;
callback(error, fileContents);
}
Of course, this is just some pseudo-code to illustrate my point.
Now, you can name your parameters in your function function(err, data) whatever you want, because they are in the scope you defined. Even if you swap their names function(data, err), they will still contain the error and file content values respectively.

How to chain two callback-type gain functions of the same object?

I have an object Word, which is a model from loopback (http://docs.strongloop.com/display/DOC/Model#Model-Model.count([query],callback)). It has a set of interfaces for working with information. Namely it has 2 methods Word.count() and Word.find()
Both methods gets data by callback. I need to ask one method after another.
this.count({}, function (err, count) {
if(err) {
fn(err);
}
else {
//here i want to call smth like
//this.find({},function(err,result){..})
//but can`t, cause "this" is undefine
}
});
How can i make a chain?
this is a common cause of js problems. A useful technique is to set it to a different variable so you can use it in a closure, like (it seems) you want to.
Does this work?
self=this;
this.count({}, function (err, count) {
if(err) {
fn(err);
}
else {
self.find(...);
//here i want to call smth like
//this.find({},function(err,result){..})
//but can`t, cause "this" is undefine
}
});

Why cant I pull the callback out of the app.get function in node and express.js?

I'm trying to do this in my server.js file:
// doesn't work... don't know why.
var findBooks = function (err, books) {
if (!err) {
return response.send(books);
} else {
console.log(err);
}
}
// Get all books
app.get('/api/books', function (request, response, err, books) {
return BookModel.find( findBooks(err, books));
});
and it gives me a 404 error when I run a jQuery xhr in the console, and the same error when I request the page in the browser. It works if I put the callback in the usual place, moving the findBooks function into the BookModel.find function where it's called and deleting the last two arguments of app.get. I'm working though Chapter 5 of Addy Osmani's Backbone.js Applications book to give you some context. Why doesn't this work? Is doing this a good thing, or am I trying something that isn't recommended?
You have two problems:
findBooks tries to access response, but response is not in scope at that point.
You're calling findBooks with err and books and passing the return value to BookModel.find, when you probably want to pass the function for find to call.
Let's first solve the second problem. Rather than calling the function, just pass it:
return BookModel.find(findBooks);
That was easy. Now, to solve the first problem, we'll need to add an extra argument to findBooks. I'll assume you put it at the start for reasons I'll detail later. Then we can change the usage to look like this:
return BookModel.find(function (err, books) {
return findBooks(response, err, books);
});
It turns out, though, that there's a more concise way to do that, using bind. bind is best known for its use in binding the value of this, but it can also be used to bind arguments:
return BookModel.find(findBooks.bind(null, response));
All together, we get:
function findBooks (response, err, books) {
if (!err) {
return response.send(books);
} else {
console.log(err);
}
}
// Get all books
app.get('/api/books', function (request, response) {
return BookModel.find( findBooks.bind(null, response) );
});

Categories

Resources