I have a question about asynchronous/synchronous when we write code in JS and I have done google search but I am still a bit confused.
I understand that we use callback functions when we want to make sure that the callback function is executed only after the asynchronous task (such as accessing database) in the outer function is complete. I understand how deserialize and serialize user works.
I am confused why when we do serialize user or deserialize user with passport.js we need a callback function like this ?
passport.serializeUser((user, done) => {
done(null, user.id);
});
If all we want is that the inner arrow function that is passed as an argument to serializeUser() to be executed only after serializeUser() is finished. Or why do we need to pass it as a callback function instead of calling that arrow function below serializeUser() ? I thought JS is synchronous so it will execute the arrow function after serializeUser() is completed anyway ?
I only found serializeUser() documentation in passport documentation on how to use it, but not its implementation so I am also confused whether serializeUser() or deserializeUser()( or any other passport functions) are asynchronous functions ?
Thank you !
It is a fragment of this function on github (https://github.com/jaredhanson/passport/blob/08f57c2e3086955f06f42d9ac7ad466d1f10019c/lib/authenticator.js).
As you can see this function takes a fn parameter. Then it checks if it is a function. If yes it pushes it to this._serializers. Later it does 'some magic' on it, I think it's not important now.
As you can read in jsdoc, serializeUser purpose is to register a function used to serialize user objects. So you pass some function which is invoked later in a code with 2 arguments which labels on that particular function level are user and done.
They left you some space which you can fill with your own code. You can tell how this will behave. They gave you an opportunity to implement your own logic.
Simple example:
function doSomeMagic(fn) {
// I do some my staff
const a = 5;
const b = 10;
// and now I let you decide what to do
// you can implement your own logic in my function
const result = fn(a, b);
console.log(result);
}
doSomeMagic((a, b) => {
return a * b;
});
doSomeMagic((a, b) => {
return a + b;
});
//output:
// 50
// 15
That's exactly what they've done. You can take my function, I give you two arguments do whatever you want. You can multiply, add, substract, whatever you want. I don't have to write separated functions to do math, I can write one, pass values as arguments and let you decided what operation you want to do. And it doesn't mean my code is going to run in an async way.
Related
As I'm currently learning coding with express/Node in order to evolved (used to C and PHP/MySQL...) I have completed the MDN tutorial on express which very well done and every thing is pretty much straight forward; my personnel project is going almost done, thanks to the Mozilla teaching team.
However, here is a point I still can't figure out as I'm still not confortable with the use of Callbacks function.
The point of dealing with asynchronous timing of execution I get, but using MongoDB and mongoose in this tutorial, I've got that queries can be executed either in two steps or in one go by using directly a callback function like creating an instance of a Schema:
// Create an instance of model SomeModel
var awesome_instance = new SomeModel({ name: 'awesome' });
// Save the new model instance, passing a callback
awesome_instance.save(function (err) {
if (err) return handleError(err);
// saved!
});
or
SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) {
if (err) return handleError(err);
// saved!
});
However, in the JS script given to fill the DB with data, it seems that both syntaxes are used, here is an example:
function authorCreate(first_name, family_name, d_birth, d_death, cb) {
authordetail = {first_name:first_name , family_name: family_name }
if (d_birth != false) authordetail.date_of_birth = d_birth
if (d_death != false) authordetail.date_of_death = d_death
var author = new Author(authordetail);
author.save(function (err) {
if (err) {
cb(err, null)
return
}
console.log('New Author: ' + author);
authors.push(author)
cb(null, author)
} );
}
What troubles me is that
"cb" is never defined,
the script works the same if I delete all callbacks from arguments "defined" in functions and their respective calling
What is the point of cb(null, author): no data need to be return, they are push to the declared array and saved to the DB at the same time.
The full script can be found here: https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js
Thanks anyone who takes time to read and answer me,
Tiago
Welcome to stack
in Js world , the function can be treated as a variable , the function is a type of variable like String , Number …etc , which may confuse you .. the callback is just a function that has a variable ( argument ) name … now swift language has implemented that pattern as well .
The functions in JS could be sent to other functions as an argument and could be returned as well.
The callback argument sent by the function caller like any other variable sent to the called function but sent as a function …
You could name it anything like cb or whatever … The cb argument is a function which means when you try to use it inside the called function it may need arguments as well like cb(null, author) .. Now imagine the cb is just a variable of type function sent from the caller to the called function.. and the cb itself as a function has to receive arguments .
I know it’s confusing especially if cb is returned as well .
Sometimes callbacks don’t receive any arguments , Again you may call them anything like callback or cb as a convention .. Usually they are the last parameter, as a convention … It just needs some imagination to understand how this confusing parameter goes in and out …
Inside your called function if you didn’t use your callback so removing it will not affect the code as you will not examine errors . BUT in node world callbacks are usually important because it does something after you finish what you’re doing .
i hope that simple illustration clarifies what you’re asked because it has confued me a lot like you .
I am originally coming from Java programming language as background. Java is strongly typed and quite explicit (I mean by that, you have to write things out, you can't just omit them). One thing, that will never get in my head is how that implicit parameter passing to javascript works...
as an example:
const observer = {
next: console.log,
error: console.error,
test: console.table,
}
observer.next('HI World!')
in next, I specify console.log which is a function, but I never say to accept a value, but in Javascript I apparently can just throw anything to functions as suffix and it takes that as an argument to its function.
Thats also how pipelining or currying basically works, it takes the remaining return values as parameters..why is that so?
Secondly, e.g in express, I have a function signature like so:
app.get('/', function (req, res) {
res.send('GET request to the homepage');
});
I actually get req and res out of my function callback is that right? those are not parameters that I pass to my callback function?
Edit: Can someone explain to me again where the REQand RES parameters are coming from? How does that construct work? Because I am defining the callback function myself, but instead of passing req and res as parameters to my callback, it seems they get passed from somewhere back to inside my callback function?!?!
A function in JavaScript is an object just like any other. This means a function can be passed around, can be assigned to variables, and essentially can be used anywhere a value can be used. This is known as first-class functions.
For example, given a simple function like this one:
function log(msg) {
console.log(msg);
}
These two functions are conceptually equivalent:
const log1 = log;
// same as
function log1(msg) {
log(msg);
}
As you can see, we can directly assign the function log to a variable like log1, ,and then we can use log1 just like we use log:
log1('foobar');
Another usage of first-class functions is to be able to pass them as arguments to other functions. A function that takes a callback like in your Express example is known as a higher-order function. The arguments of the callback are provided by the caller of that callback. In your case Express provides the req and res arguments.
Using callbacks is a form of inversion of control. You are passing control of that part of the program to the caller.
There is an article I've seen about the callbacks in javascript. https://codeburst.io/javascript-what-the-heck-is-a-callback-aba4da2deced I know that I can understand it by reading the article. However, I'm getting confused of the callback while studying the module export in node.js
Callback - A callback is a function that is to be executed after another function has finished executing
Callback in javascript
function doHomework(subject, callback) {
console.log(`Starting my ${subject} homework.`);
callback();
}
doHomework('math', function() {
console.log('Finished my homework');
});
Module export in node.js
//app.js
const logger = require('./logger');
logger.log(10, 10);
//logger.js
const multiply = require('./multiplication');
function log(valueOne, valueTwo) {
multiply('The result is ', valueOne, valueTwo);
}
module.exports.log = log;
//
function multiply(speech, valueOne, valueTwo) {
let result = valueOne * valueTwo;
return console.log(speech + result);
}
module.exports = multiply;
and ran the node app.js on my terminal.
The result that I got from running the node app.js is The result is 100 and that is correct.
But my question is
Does the approach that I did on the node app is consider as callback as well?
Callback - A callback is a function that is to be executed after another function has finished executing
That's not a correct definition of "callback." Unless that definition had major caveats on it you didn't quote, I wouldn't continue to use whatever resource you got that from.
A fairly broad definition of a callback is:
A callback is a function you pass to something else (as a function argument, property value, etc.) that the other thing will call when its defined criteria for calling the function are met.
Some might argue for a narrower definition:
A callback is a function you pass to another function for that other function to call back when its defined criteria for doing so are met.
Examples of callbacks:
DOM event handlers, although we usually call them "handlers" rather than callbacks. (Broad definition.)
The function you pass to Array.prototype.sort to compare array elements. (Both the broad and narrower definitions.)
The function you pass to new Promise to start the asynchronous operation the promise will observe (called the "promise executor function"). (Both the broad and narrower definitions.)
The function you pass to Array.prototype.map to transform elements. (Both the broad and narrower definitions.)
The function you pass to a promise's then, catch, or finally method.
The function you pass to fs.openFile that Node.js will call when the file has been opened (or the operation has failed). (Both the broad and narrower definitions.)
...and many others.
Notice that many of those (2, 3, and 4) are called before the function calling them has finished executing.
Does the approach that I did on the node app is consider as callback as well?
No. Although you use multiply in log, it's just a function you call from log, not a callback. This would be a callback:
function multiply(a, b, cb) {
cb(a * b);
}
function showResult(msg) {
console.log(msg);
}
multiply(7, 6, showResult);
showResult is used as a callback when calling multiply.
I don't entirely understand your question. However, from what I gather, module.exports does not make a function a callback function explicitly. The purpose of module.exports is to allow access to that function when requiring the relevant .js file...as seen in your example.
Your log() function is a not a callback as you are simply passing in parameters and then using those values to call the multiply function and output the result.
When you call the multiply function you are simply calling it like so:
multiply('some text', 10, 10)
For this to be a callback it would have to take a function as it's final parameter, i.e.:
multiply('some text', 10, 10, function(err, data) {
// ...
})
This also goes for the log function, and any for that matter.
So, unless the final parameter of a function is a function, it is a not a callback. module.exports purely allows access to that function or the functions you specify in the object, for example:
module.exports = {
functionOne: someFunctionName,
functionTwo,
functionThree
}
If the name of the function is the same name as what you are trying to export you do not need to specify a value to the key.
I have been looking for assistance with setting up an IndexedDB for web storage, and I have run into a problem that I cannot find a good answer to. After I have successfully setup/opened the database I am having trouble passing the variable that contains the database information to access it later. Here is my code, I have been following a guide from MDN :
const DB_NAME = 'database-name';
const DB_VERSION = 2;
const DB_STORE_NAME = 'users';
var db;
function openDb() {
console.log('openDb ...')
var request = indexedDB.open(DB_NAME, DB_VERSION);
request.onsuccess = function(event) {
db = request.result;
console.log("openDb DONE");
};
request.onerror = function(event) {
console.log(request.errorCode);
};
request.onupgradeneeded = function(event) {
console.log('openDb.onupgradeneeded');
var store = event.currentTarget.result.createObjectStore(DB_STORE_NAME, { keyPath: 'id', autoIncrement: true });
store.createIndex('age', 'age', { unique: false });
};
}
function getObjectStore(store_name, mode) {
var tx = db.transaction(store_name, mode);
return tx.objectStore(store_name);
}
When getObjectStore is called the variable db is undefined. My knowledge of javascript is very limited and some concepts I don't get. The guide doesn't not show anything special being done and their demo works as is. Some other guides have mentioned implementing a callback, but they don't show how its done nor do I understand the concept of callbacks. Any help is appreciated. Thanks.
Unfortunately you need to learn about a relatively complicated concept usually referred to as asynchronous JavaScript before proceeding to use indexedDB. There are already several thousand questions related to AJAX on stackoverflow. I am trying to think of the most polite way to say this, but basically, the answer you are looking for is already provided by these other questions, and by many other websites. Nevertheless, here are some quick tips.
First, your approach is never going to work. You cannot skip over learning about async.
Second, do not use the setTimeout trick to get it to work. That is horrible advice.
Third, at a general level, a callback is simply a word used to describe a function when the function is used in a particular way. Specifically, a callback refers to a function that is passed as an argument to another function, where the other function then maybe calls the function at some later point in time. More specifically, a callback is generally a function that is called at the end of the function it is passed to, when the function has completed.
For example:
function a(b) { alert(b); }
function c(d) { d('hi'); }
c(a);
That might look a bit confusing at first but it is the simplest thing I can describe off the top of my head. In the example, the final line calls function c and passes in function a. The effect of the code is that you see 'hi' as a browser alert. In this example, the function a is passed as a parameter/argument to function c. Function c uses the name d for its one and only argument. c calls d with the string 'hi'. When describing this example, we would say that argument d represents a callback function passed to function c. We could also say that function a is the particular callback function used by function c. So that is basically it. When you pass a function in as an argument and the other function calls the passed in argument, you are using a callback.
Then things gets way more complicated, because you have to learn about how to read and write asynchronous code. Properly introducing it would take several pages. Here is an extreme crash course.
You have traditionally been writing synchronous code, even if you did not call it that. Synchronous code runs exactly when you expect it to, in the order that you write your statements. Here is a brief example of typical sync code:
function sum(a, b) { return a + b; }
alert(sum(1, 2));
Simple stuff. The next example is code that uses a callback, but is still synchronous.
function doOperation(op, num1, num2) { return op(num1, num2); }
function sumOperation(num1, num2) { return num1 + num2; }
var result = doOperation(sumOperation, 1, 2);
alert(result);
Here we passed the sumOperation function into the doOperation function. sumOperation is the callback function. It is the first argument with the name 'op'. Still pretty simple stuff. Now consider the next example. The point of the next example is to show how we pass control to the function to do something. Kind of like how goto/labels work.
function doOperation(op, num1, num2) {
var result = op(num1, num2);
alert(result);
return undefined;
}
function sumOperation(num1, num2) { return num1 + num2; }
doOperation(sumOperation, 1, 2);
Notice how doOperation no longer returns a value. It has the logic within its function body. So once we call doOp, the browser starts running the code inside doOperation. So we switched from the outer context into the body of the function. Also, because doOperation doesn't return anything, we cannot do anything with its return value. The logic is locked inside the body of the doOperation function. The code still works about the same, its just that now we are not returning anything from doOperation, and now the logic is inside doOperation instead of outside in the main/global context.
Now an example that uses setTimeout. This is completely unrelated to the suggestion of using setTimeout.
function doOperation(op, num1, num2) {
setTimeout(function runLater() {
var result = op(num1, num2);
alert(result);
return undefined;
}, 1000);
return undefined;
}
function sumOperation(num1, num2) { return num1 + num2; }
doOperation(sumOperation, 1, 2);
The point here is to understand that we use a callback (named runLater in this example), and that the code inside the callback does not run immediately. Therefore, we can no longer say it runs synchronously. We instead refer to the statements constituting the body of the callback function as asynchronous. So now an alert appears after 1 second. Notice how we cannot return anything from runLater. Also notice how we cannot return anything from doOperation. There is nothing to return. There is no way to get the value in the 'result' variable out of the scope of runLater. It is locked in there.
Let's try almost the same thing, but try to have runLater set a variable. Also, I am going to omit 'return undefined' because that is what every function without a explicit return statement returns.
var aGlobalResult = null;
function doOperation(op, num1, num2) {
setTimeout(function runLater() {
aGlobalResult = op(num1, num2);
}, 1000);
}
function sumOperation(num1, num2) { return num1 + num2; }
doOperation(sumOperation, 1, 2);
alert(aGlobalResult);
Hopefully you are catching on to the problem. First off, runLater does not return anything, so doOperation does not return anything, so we could not even try to do something like aGlobalResult = doOperation(...);, because that would not make any sense. Second, the result here is that you will see an alert 'undefined' because the alert statement executes prior to the statement that assigns a value to aGlobalResult. This is even though you wrote the assignment statement higher up (earlier) in the code, and the alert is later. This is the brick wall some newer developers run into right here. This is indeed confusing for some. aGlobalResult is undefined here because setTimeout does not set it until later. Even if we passed in 0 milliseconds to setTimeout, it is still 'later', meaning that the assignment happens at a later point in time, after the alert. The alert message is always going to be undefined. There is absolutely nothing you can do to avoid the way this works. Nothing. Period. Stop trying. Learn it, or give up entirely.
So, how does one typically write code that behaves or involves asynchronous stuff? By using callbacks. Which again means that you can no longer use return statements to assign values to outer scope variables. You instead want to write functions and pass around control to various functions. In other words, instead of:
function a() {}
function b() {}
function c() {}
a(); b(); c();
you write code like this:
function a(callback) {
var asdf = 1+2; // do some stuff in a
alert('a finished');
// a has now completed, call its callback function, appropriately named callback
callback();
}
function b(callback) {
var asdfasdfasdf = 3 + 4;
alert('b finished');
// call the callback
callback();
}
a( function(){ b(function() { alert('both a and b finished'); }); });
This is more formally known as continuation passing style, or CPS.
So, that is an example of the very basics of writing callback functions and basic asynchronous code. Now you can start to use indexedDB. The first thing you will notice is that the function indexedDB.open is documented as asynchronous. So, how can we use it? Like this:
var someGlobalVariable = null;
var openRequest = indexedDB.open(...);
openRequest.onsuccess = function openRequestOnSuccessCallbackFunction(event) {
// Get a reference to the database variable. If this function is ever called at some later
// point in time, the database variable is now defined as the 'result' property of the
// open request. There are multiple ways to access the result property. Any of the following
// lines works 100% the same way. Use whatever you prefer. It does not matter.
var databaseConnection = openRequest.result;
var databaseConnection = this.result;
var databaseConnection = event.target.result;
var databaseConnection = event.currentTarget.result;
// Now that we have a valid and defined databaseConnection variable, do something with it
// e.g.:
var transaction = databaseConnection.transaction(...);
var objectStore = transaction.objectStore(...);
// etc.
// DO NOT DO THE FOLLOWING, it does not work. Why? Review the early descriptions. First off
// this onsuccess callback function does not return anything. Second off this function gets
// called at some *later* point in time, who knows when. It could be a nanosecond later.
someGlobalVariable = databaseConnection;
};
Hopefully that sets you on the path.
Edit: I thought I would add a bit more of an intro. A related concept you need to learn that I did not explain clearly enough regarding control is the difference between imperative and declarative programming.
Imperative programming involves executing a series of statements in the order you wrote. You are the caller and are in control. Imperative code looks like this (fictional code):
var dbConn = dbFactory.newConnection('mydb');
var tx = dbConn.newTransaction();
var resultCode = tx.put(myObject);
if(resultCode == dbResultConstants.ERROR_PUT_KEY_EXISTS) {
alert('uhoh');
}
Declarative programming is subtly different. With a declarative approach, you write functions, and then you register (aka hook or bind) the functions to the JavaScript engine, and then at some point later, when it is appropriate, the engine runs your code. The engine is the caller and is in control, not you. Declarative programming involves callbacks and looks like this (fictional code):
dbFactory.newConnection(function onConnect(dbConn) {
dbConn.newTransaction(function onNewTransaction(tx) {
tx.put(myObject, function onPut(resultCode) {
if(resultCode == dbResultConstants.ERROR_PUT_KEY_EXISTS) {
alert('uhoh');
}
});
});
});
In this example, the only thing you called was the fictional dbFactory.newConnection function. You passed in a callback function. You did not call the callback function yourself. The engine calls the callback function. You cannot call the callback function yourself. This is kind of the whole idea behind why JavaScript engines can allow you to write asynchronous code. Because you don't get to control the order of execution of statements/functions. The engine gets to control it. All you get to do is write your functions, register them, and then start a chain of callbacks (the sole imperative line, the starting statement).
So this is why a function like getObjectStore in your question will not work. You are trying to call the function yourself, but that is backwards. You can only write a function and register it (somehow hook it up as a callback somewhere) and then the engine, not you, calls it at some later point in time.
Hopefully this is not more confusing, but you could actually write your function getObjectStore if you really wanted to by passing in the database variable to the function as its first argument. This leads to the logical next question, how to get a valid database variable to pass into the function. You cannot get one in a global context (reliably). Because the connection variable is only valid within the context of the onOpen callback function. So you would have to make your call to this function from within the onOpen function. Something like:
function getObjectStore(db, name, mode) {
var tx = db.transaction(name, mode);
var store = tx.objectStore(name);
return store;
}
var openRequest = indexedDB.open(...);
openRequest.onsuccess = function onOpen(event) {
// get the connection variable. it is defined within this (onOpen) function and open.
var db = this.result;
// call our simple imperative helper function to get the users store. only call it from
// within this onOpen function because that is the only place we can get the 'db' variable.
var usersStore = getObjectStore(db, 'users', 'readwrite');
// do something here with usersStore, inside this function only.
};
In this example from Angularjs Docs there is some *magic*, which i can't figure out.
Here is a code:
var User = $resource('/user/:userId', {userId:'#id'});
var user = User.get({userId:123}, function() {
user.abc = true;
user.$save();
});
And one thing confusing me - how we can refer to user object inside callback and get retrieved data, when it is necessary to populate user first. But to do so value should be returned from User.get().
Like that:
call User.get() → return from User.get() → call function() callback
But after return it is not possible to execute anything, right?
It is absolutely possible to return the user and still have not executed the callback, and this is what this code example is showing.
The implementation of User.get might be something like:
User.prototype.get = function(parameters, callback) {
var user = {
abc: false
}
// do other stuff to construct the object
someLongAsyncOperation(callback);
return user;
}
Here the user is returned, but there is still a callback to be completed. Then within that callback the user can be accessed via closure scope. someLongAsyncOperation could be anything that later calls callback, you could try it out yourself with something as simple as a setTimeout or Angular's $timeout.
Its not in my opinion a great pattern, and it might be better to include the created user as a parameter in the callback - but it would work.
User.get() returns a blank object and performs an async GET to /user/123. This empty object is assigned to the user variable in the function scope.
The rest of the function (if there is any) executes and the function returns.
When the async call returns, the get() method populates the existing blank object's properties with the properties of the object returned, so the user variable now has the results of the callback.
The get() method calls the callback you specify. It has access to the function's user variable that is now populated from the async call.