How the callback is executed in this function? - javascript

const getData = (cb) => {
setTimeout( () => {
cb({ data: ['there', 'is', 'stuff', 'here'] })
}, 100)
}
getData( data => {
console.log(data);
});
Here is the example of the javascript callback. Could some one let me know how this functions is executed into the javascript callback?
Here what is the function inside getData(cb) ? How it will be executed ? How the functions is passed as callback inside cb and return to the console.log
Regards.

The function inside getData is a callback being passed to setTimeout, which is one way to schedule a call to a function to happen in the future. In this case, it's asking for that callback to happen roughly 100ms later. getData returns before that happens.
The setTimeout callback is a closure¹ over the context where it's created, which means it has access to cb even after getData has returned. So when the browser's timer calls the callback, the callback can call cb. The call to cb uses an object literal to create an object to pass to cb.
In the call to getData, the author is passing a function as cb that logs the data it receives.
So:
getData is called, passing in a function that will log the argument it gets.
getData calls setTimeout to schedule a callback in about 100ms, passing in another function for the timer to call.
getData returns.
About 100ms later, the browser's timer subsystem triggers a call to the callback passed to setTimeout.
That callback creates an object and calls cb, passing the object to it.
That callback (the one passed to getData) logs the data object it receives.
¹ "closure" — see: SO, my anemic blog

In order to understand the code you can just simplify it by naming the anonymous functions. One example could be:
function logData(data) {
console.log(data);
}
const getData = (cb) => {
// `cb` is `logData` function when `getData` is called
function timeoutCallback() {
var data = { data: ['there', 'is', 'stuff', 'here'] };
cb(data);
}
setTimeout(timeoutCallback, 100)
}
getData(logData);
Does that make sense?

1- first global execution context created
2- get data function will be called then it will wait for 10 seconds inside the event loop then it will be come to execution context and printed to console.

Related

What is the difference of callback and module exports?

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.

Debounce and return

I'm having an issue with this piece of code:
function aFunction(){
....
var deferred = $q.defer();
debounce(function () {
deferred.resolve(service.subscribe0(data));
}, 350);
return deferred.promise;
}
The returned promise is never resolved. Debounce function is a 3rd party function with a lot of downloads from NPM, so I can be sure it works.
Can it be because the return statement "removes" the scope of the function? How can I avoid this and resolve the promise?
You misunderstand what debounce() does.
debounce() is a function that accepts a function, and returns a function. The returned function will only call the passed callback after N milliseconds of silence (that is, if you call the debounced function very quickly in sequence, only the last call will take effect, after the time elapses).
debounce() itself doesn't call the function you pass it. So, deferred.resolve() never gets called.
I would expect something like:
const getData = data => Promise.resolve( service.subscribe0( data ));
grid.addEventListener( 'scroll', debounce( getData, 350 ));
We want the grid to update itsself on scroll, but debounce it so it won't flood the service with calls. So we have to debounce the function tied to the scrolling instead of the data call, since there's no link between two different data calls.

Nested Callback stuck in Loop

I have nested callback that is setup as following:
function submitForm() {
BuildContent($('#Content').val(), '', true, submitForm)
PerformSubmit();
}
function BuildContent(textWithUrl, textSource, isSubmit, callback) {
console.log("GetWebContent in Progress");
GetWebContent(sendurls, BuildContent)
console.log("GetWebContent done");
callback();
}
function GetWebContent(content, callback) {
$.ajax({....
sucess:function(msg) { .....
callback();
}
}
expected outcome is when submitForm is called it calls Build Conetent which calls GetWebContent. o*nly after the ajax call in inside GetWebContent is sucessfull then only PerformSubmit(); is executed.* for some reason it loops and JS hangs and becomes unresponsive and BuildContent console logs keeps prininting in loop.
The BuildContent callback called just after the console.log is the function submitForm
which promptly calls BuildContent hence an endless loop.
Without doing an in-depth analysis, I would suggest removing the call callback at the end of BuildContent and passing it instead as the second parameter of the call to GetWebContent.
After a bit more thought, in submitForm teh callback you send to BuildContent should be PerformSubmit. My alterations to buldContent stand.
It looks like you have a misunderstanding of how callbacks work. When a callback returns, it does not resume execution where it left off. The function calling the callback finishes immediately.
You need to structure the code like so:
function submitForm(){
BuildContent($('#content').val(), '', true, performSubmit);
}
function BuildContent(textWithUrl, textSource, isSubmit, callback){
console.log("GetWebContent in Progress");
GetWebContent(sendurls, callback);
}
function GetWebContent(content,callback){
$.ajax({...
success:function(msg){ ....
console.log("GetWebContent done");
callback(); <-- performSubmit is being called here,
after all of the asynchronous work is done
}
});
}
You'll notice that I pass the performSubmit along as the callback to each of these functions, and then call it in the success function.
Anything AFTER the GetWebContent call within BuildContent will execute immediately, so you can't expect the second call to console.log to be AFTER the ajax request is finished.

How can I add a callback to the .apply() method?

In my code, I have an array of function calls. I loop over these calls and use .apply() to call them. The problem is that if the call of the new function takes any sort of time, the loop will .apply() and call the next function before the prior function is finished. >.< Here is an example:
function someFunc(element, calls){
if(calls.length){
fn = calls[0];
calls.shift();
fn.apply(element, args);
someFunc(element, calls);
}
}
So if there was a callback on the apply function then this could work how I want it to. i.e.
function someFunc(element, calls){
if(calls.length){
fn = calls[0];
calls.shift();
fn.apply(element, args, function(){
someFunc(element, calls);
});
}
}
I also have a question about calling someFunc inside of a callback function. The functions in my calls array affect my element variable. So I want to make sure after it gets changed that it gets passed to someFunc in the callback so the next function can manipulate it as well. Sometimes I just get confused with the this context. :)
If it helps, I am using jQuery. I know how to add callbacks to jQuery methods but I don't know how to do that when I'm dealing with native JavaScript code. How can I add a callback to the .apply() method?
Make sure that every function you call returns a promise. You can then "wait" for that promise to be "resolved" before continuing with the next function in your list:
function someFunc(element, calls) {
if (calls.length) {
var fn = calls.shift();
fn.apply(element, args).done(function(el) { // what's args?
el = el || element; // default to previous element if necessary
someFunc(el, calls);
});
}
}
with each function looking something like:
function myFunc1(el) {
var def = $.Deferred();
// do something async, and "resolve" the deferred object in the async callback
...(function() {
def.resolve(el); // this "el" will get passed to the next function
});
return def.promise();
}
If the asynchronous task is an AJAX call you can just return the jqXHR result of $.ajax directly instead of creating a new deferred object.

Having problem with a callback method for this jQuery getJSON AJAX call

i've got a utility .js file that grabs some data via Ajax. Now this utility method doesn't know who will call it.
So when the Ajax async completes, it needs to send an object back to the caller. I'm not sure how to do this :(
This is the code I have...
function someMethod(a, b, c) {
// ... stuff ...
// Now fire it off, asynchronously!
var request = $.getJSON(url, function (jsonResult) {
var result =
{
json: jsonResult,
contentLength: request.getResponseHeader("Content-Length")
};
// TODO: Now return this result to the caller.
});
}
of course, i can't use return result; because this is async. I feel like i need to pass in a parameter that is the function which the ajax code above needs to call, when the result has been async finished. Just not sure how .. because remember .. this is method has no idea who is calling it .. so it doesn't know about any other methods and stuff.
Any ideas, please?
You are right. You will need to pass in the function to "someMethod" so that you can return the data to it. Depending on what the callback function does you might also need to set it's context properly by using the call or apply methods. The "context" is what what the "this" keyword will be set to in the callback function.
If your callback function doesn't make any references to the keyword "this" then you can ignore the use of call() or apply() and just call the function as in the second example. (e.g. callback(result));
function someMethod(a, b, c, callback, context) {
// ... stuff ...
// Now fire it off, asynchronously!
var request = $.getJSON(url, function (jsonResult) {
var result =
{
json: jsonResult,
contentLength: request.getResponseHeader("Content-Length")
};
// Now return this result to the caller. With the context set
callback.call(context, result);
// Example of callback without setting the context
//callback(result);
});
}

Categories

Resources