Callback functions vs hardcoding inner function? - javascript

I'm reading about Callback functions in Javascript, and W3 schools reports that a callback is simply where a one function calls another, the latter of which is an argument that's passed to the first in the form of:
const callback = () => {
console.log('callback executed.');
};
const myFunc = (callbackFunc) => {
console.log('myFunc started')
callbackFunc();
};
myFunc(callback);
My question is, in practice, how is this any different than hardcoding the callback into MyFunc's definition? eg
const myFunc = () => {
console.log('myFunc started')
callback();
};
I've heard callback functions mentioned in the same breath as async; so my best intuition is that this design allows the exact function, to be passed as an argument to myFunc, to be decided dynamically based on some logic external to myFunc.
However, I'd like confirmation/clarification and amplifying details.

Your intuition is correct but the benefit and the use of it is tremendously big.
That's allow Separation of Concern and Dependency Inversion.
And the fact we can pass function as any other value and return value (it's what we called high-order function) allow us to process composition of it.
Then we can code in purely functional way without the need of class to handle some state which is an Object Oriented Way. Both paradigm can be handle in JS because it's a multi-paradigm programming language but be aware of what we do is essential to not transform the code in a entire mess.
When you will study Promise you will see how to take advantage of callback to handle side-effect in a really canny way such we can manage side-effect and push it aside to keep reasonning in a more mathematical way.
For instance imagine:
const callHttp = (callback) => {
const res = // do asynchronuous operation taking time
callback(res);
};
You can dynamically pass down the result to handle it only after the delay execution to get the info. In such way you can program in a really neat way to manage side-effect of any types of event.
Enjoy your path through Javascript ;)

Let's say we're building this web app that lets users upload images and then we can apply all sorts of image processing effects on them, like turning them into grayscale, sepia or even sharpening them.
Initially, we thought of just creating a function called "applyEffect" that takes in the image and a string representing the desired effect. But, as we started adding more effects, we realized that the switch statement inside the function was becoming a nightmare to maintain. Plus, every time we wanted to add a new effect, we had to go back and modify the "applyEffect" function.
function applyEffect(img, effect) {
switch (effect) {
case "grayscale":
applyGrayscale(img);
break;
case "sepia":
applySepia(img);
break;
case "sharpen":
applySharpen(img);
break;
// etc.
}
}
Now, let's try to solve it with a separate callback functions for each effect, like "applyGrayscale", "applySepia" and "applySharpness". Then, we created a new function called "applyEffect", that takes in an image and a callback function as arguments.
function applyEffect(img, callback) {
callback(img);
}
Now, whenever we want to apply an effect to an image, we just call "applyEffect" and pass in the image, along with the appropriate callback function. It's way more flexible and easy to maintain.
applyEffect(myImage, applyGrayscale);
applyEffect(myImage, applySepia);
applyEffect(myImage, applySharpen);
By using callback functions, the applyEffect function is closed for modification (no need to change the applyEffect function when adding new effects) and open for extension (easily add new effects by creating new callback functions and passing them to applyEffect).
This is one of the SOLID principles for writing maintainable and scalable code.

Related

How to conceptualize multiple callbacks, a.k.a. how do you think through code like this?

For example, take this code (source : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
// --file.js--
function getJSON(url, callback) {
let xhr = new XMLHttpRequest();
xhr.onload = function () {
callback(this.responseText)
};
xhr.open('GET', url, true);
xhr.send();
}
export function getUsefulContents(url, callback) {
getJSON(url, data => callback(JSON.parse(data)));
}
// --main.js--
import { getUsefulContents } from 'file';
getUsefulContents('http://www.example.com', data => {
doSomethingUseful(data);
});
I often come across a situation where I need to build something like this, or read it, and Im always so slow at it, so, is there a better way to conceptualize this pattern?
Heres my thought process currently (how I read the above) :
Ok, we have 2 files, one is getting a function imported from the other. (easy peasy)
The imported function is getting called, and passed a URL and callback function. (easy peasy lemon squeezy). This callback function takes 1 parameter ('data') and passes it to doSomethingUseful(data). (I believe were blocking at this point)
In file.js, getUsefulContents was called and passed the URL and callback.
getJSON is called, and passed the URL and a callback... Did everything just pass right through getUsefulContents? Why do we need it? (Confused back and forth)
...Ok whatever, getJSON now has the URL and callback. It creates a xhr object, reacts to an onload event by calling the callback (finally!) passing this.responseText to it (thats the data).
the callback runs, which runs doSomethingUseful(data) and were done.
This takes me quite a while to analyze on a regular basis. Are there any conceptual tricks or better ways to analyze this?
Not really any tricks to conceptualizing it all together, but that goes against one of the main tricks we use as programmers.
That trick is to break the program down into functions to hide what they're doing inside. Instead of trying to understand everything as one big long flow, just understand that getUsefulContents() gives you some useful contents. Don't worry about how it's doing it, unless you're working on changing getUsefulContents().
In general, you can think of each function as a black box. You feed it a, it spits out b. That's as much as you usually need to understand about it (unless you're mucking around inside it).
If you need to understand the whole program in minute detail, it's going to take take to understand. It's a lot to understand. That's why we use functions at like we do.
With callbacks, it looks a little different, but it's still the same. For a function that accepts a callback, you give it a and something to call when it's done. It calls that something and spits out b. Beyond that, you don't usually need to worry about it.

rxjs using promise only once on subscribe

I wanted to use rxjs for the first time but am a bit stucked 'cause it doesn't behave exactly like I want it to: In my scenario I want to create an observable from a promise. But I want the promise only being called once (not on every subscription) and I want it not being called on creation time (defer the call to the first subscription).
First I tried this:
var source = Rx.Observable.fromPromise(_this.getMyPromise())
which causes a call to the getMyPromise function right on creation time. This is not satisfying because at that time I don't know if the source really will be used.
Then I tried:
var source = Rx.Observable.defer(function() { return _this.getMyPromise() })
which causes a call to the getMyPromise function each time a new subscription is being made to source. This makes way too many unnecessary calls to the web server. The Rx.Observable.create function seems to have the same issue.
So what is left or what am I missing?
.shareReplay() does this, e.g.:
var source = Rx.Observable.defer(function() { return _this.getMyPromise() }).shareReplay();
If you're using rxjs5, you'll want to read: Pattern for shareReplay(1) in RxJS5
In answer to your comment below, I can think of a fairly straightforward extension to the above logic that will do what you want, but it has a caveat. Let's say the events you want to use to trigger a "refresh" are represented in a stream, s$, then you could do something like:
var source = Rx.Observable.of({}).concat(s$)
.flatMapLatest(function() {
return Rx.Observable.defer(function() {
return _this.getMyPromise()
})
})
.shareReplay(1)
What we have here is a stream starting with a dummy object to get things rolling, followed by a stream consisting of your refresh events. Each of these is projected into a new observable created from a fresh invocation of your getMyPromise method, and the whole thing is flattened into a single stream. Finally, we keep the shareReplay logic so we only actually make calls when we should.
The caveat is that this will only work properly if there's always at least one subscriber to the source (the first subscription after all others are disposed will run the promise again, and will receive both the previously-cached value and the result of the promise it caused to run).
Here is an answer that does not require at least one subscriber at the source at all times using a simple helper:
var _p = null;
var once = function() { return _p || (_p = _this.getMyPromise());
var source = Rx.Observable.defer(once);
Or if you're using lodash, you can _.memoize your getMyPromise and get this automatically.

Creating a jQuery "object" that is available between _layout and views in ASP.NET MVC

I am coding in ASP.NET MVC 5.2, and using jQuery as my primary script library. I am having a bit of a problem though, with the disparity between _Layout and views that use that layout.
Essentially, it goes like this
_Layout has some script that needs to run (initial wiring, progress bar, splash screen, etc)
Inheriting View has some script that needs to run (unique to that view)
_Layout has additional scripts that need to run after the view's unique scripts.
I have been trying a lot of ways to solve this, but it is actually proving to be a big problem. I have been frequently told that I should not create objects on the global namespace, so I am wondering if there are any other options to creating a script object that I can access in both views that isn't as damaging as global objects.
I have tried promises, and that is getting frustrating. I have tried events, and that doesn't really help because I cannot figure out what to attach the events to. I am told not to attach them to $(document), but that is really one of the only things that will be shared between the view and the layout.
I understand that global objects are not considered good in javascript, but at this point I'm not sure what other options I have to make sure things execute in the right order.
Update
The issue is more about "tooling" than it is about run time. It is true that when the actual view loads and runs, it is all pressed into one big happy page, and would work just fine. The issue is mostly that I have to split up the logic in the tooling (Visual Studio) to keep it from throwing errors and getting confused.
So I suppose it is more accurate to say it is a pseudo-problem.
I have attempted to split up the logic like this, but I think this is just another way of declaring a global object. I got the idea from the Q.js library.
Tasks.js
(function(definition) {
// assign the task system
tasks = definition();
})(function() {
var list = [];
function tasks() {
};
tasks.start = start;
tasks.enqueue = enqueue;
/*
* start the task queue.
*/
function start() {
// make sure to raise a started event for things that need
// to monitor it.
$(this).trigger("started");
};
function enqueue(f) {
// add the potential function to the queue to be processed later.
list.push(f);
$(this).trigger("enqueue", { item: f });
};
return tasks;
});
example usage
$(function(){
$(tasks).on("started", function(){
console.log("event called");
});
console.log("tasks", tasks);
tasks.start();
});
There are a number of ways you could go about this:
Use RequireJs to define Tasks as a module, then:
require(['tasks'], function(tasks){
$(tasks).on("started", function(){
console.log("event called");
});
console.log("tasks", tasks);
tasks.start();
});
Use a global object, but namespace it:
Ciel = Ciel || {};
Ciel.tasks = Ciel.tasks || function(){
var list = [];
...
};
Tie your data to a specific dom element:
<div class="ciel-tasks"></div>
...
$(function() { $('.ciel-tasks').each(function() {
var tasks = $(this);
...
});
It's not really clear what you're describing. From JavaScript's perspective there's no such thing as "_Layout" and "Inheriting View." There's only the resulting DOM delivered to the browser. Any JavaScript code within that DOM can operate on anything else in that DOM. So I'm not sure what any of this has to do with global namespace, events, $(document), etc. Perhaps you're overcomplicating the issue by assuming disparity between your views when, client side, no such disparity exists?
_Layout has additional scripts that need to run after the view's unique scripts.
This sounds like it's just a matter of providing callbacks for operations so that they internally execute in the correct order. For example, if the desired order is:
Layout executes initializeLayout()
View executes initializeView()
Layout executes completeLayout()
Then you can pass these to one another as callbacks and the functions can internally execute those callbacks. So in your Layout you might have something like this at the very top (such as in the header, as long as it's before the view is rendered):
<script type="text/javascript">
function initializeView(){} // placeholder for view-specific initialization
</script>
Then at the bottom with the rest of your scripts:
initializeLayout();
initializeView(completeLayout);
What this does is provide your views with an opportunity to overwrite that initializeView function. If the view defines its own function called initializeView then that one will be executed instead of the placeholder one defined in the layout (remembering that the layout and the view are all one page to JavaScript).
(This also assumes you've elsewhere defined a completeLayout function, since that's what you want to execute after the view is initialized.)
Then in your view you can define that overwriting function:
function initializeView(callback) {
// do some stuff...
if (typeof callback == 'function') {
callback();
}
}
That will execute your view initialization code and then when it's complete will invoke the callback which was provided by the layout, so the layout will then execute its post-view-initialization code. (Naturally, if any of this "initialization" code is asynchronous, you'll want to invoke callbacks in response to those asynchronous callbacks, etc.)

How to synchronize access to private members of a javascript object

I have a Javascript object created as follows:
var ccStatTracker = (function (){
ccmap:{
"1":["1","2","3","4"],
"2":["4","5"];
}
return {
modifyCCMap: function (){
// Code which takes following actions:
// - adds/removes keys.
// - modifies arrays stored as values against the keys in the map.
}
}
)();
I have a DHTMLXGrid component which displays grid in the form of rows and columns.
When I edit any cell in the grid, "onEditCell" event is called.
Now, I want to call ccStatTracker.modifyCCMap() from an event handler function attached to "onEditCell" event. As I go on modifying the cells, this event will be called asynchronously which will in turn call a function "modifyCCMap" which will modify private member "CCMap" of my Javascript object. So the latest state of my CCMap as seen by two calls might be different right? So what is the best way to handle this? Is there something as "Synchronized" in Javascript as in Java?
Please help me as it will determine the approach we want to take for implementing this.
JavaScript is single-threaded (web-workers aside for a moment), nothing happens asynchronously (or everything for that matter) - all code: event handlers, timeouts, callbacks, etc. - run in the same thread, one after another.
Thus you don't need any synchronization in JavaScript. Any given piece of code in JavaScript is guaranteed to be executed by only a single thread. How cool is that?
See also
JavaScript equivalent of SwingUtilities.invokeLater()
"atomic" operation desturbed by asynchronous ajax callbacks
Are there any atomic javascript operations to deal with Ajax's asynchronous nature?
how is async programming (promises) implemented in javascript? isn't javascript a ui-threaded environment?
...

Javascript: How do you make function2 execute only after function1 is completely finished?

I have some code, with the order of the functions in the order I want them executed. However, they seem to at the same time (they begin sequentially within microseconds of eachother presumably).
The problem is that some of the functions include animations. How do I make it so the next function doesn't execute until the previous functions are completely finished???
Following is some of my code. I created a callback chain thinking that it would be the solution, but indeed it is not. The functions themselves call jQuery animations. I'm guessing i need to use some type of notofication from jQuery to tell me when animations are done. Anyhow, any advice is greatly appreciated!
show_loader(0, function() {
close_box($target_close, '/', '#' + $target_close.attr('id') + ' .post_wrap', function() {
open_box($target_open, event.value, '.wide-col', function() {
hide_loader(function() {
scroll_to_content($target_open, function() {
});
});
});
});
});
To be precise, I want the scroll_to_content() function to be executed after all the previous actions have been completed in their entirety. Currently, it executes at the same time as everything else, and therefore my page scroll is completely off because the size of my content continues changing after scroll_to_content() is finished.
Callback chains are basically the solution but I suspect you're not threading your callbacks correctly in your calls to jQuery. $.animate(...) has an optional complete callback-- that's where you want to pass the function that should execute after your initial animation finishes. All of the Effects in jQuery UI should have a similar optional argument.
You can use a similar pattern yourself in order to chain event handlers, for instance:
function handler(event, callback) {
// do some work
// ...
callback();
}
This strategy for chaining function evaluations is called continuation-passing style and is handy in a lot of situations. Be careful using it, however, as many people find it more confusing to read than a traditional, sequential implementation.
http://api.jquery.com/queue/
Sorry, I don't have enough time to go into detail, but as the previous commenter said, queues are what you want to be focusing on to solve this problem.
you have 3 options:
1- Split your animations into multiple chained animate() calls.
This is an example to clarify it for you.
2- Follow the answer posted by #dml.
3- Try to use this plugin to add delays between your calls (don't know if it can fix this scenario or not, give it a try)
http://www.evanbyrne.com/article/jquery-delay-plugin

Categories

Resources