10

Hi! I am learning about callbacks and I understand that callbacks can be either synchronous or asynchronous.

I was reading about callbacks on https://www.w3schools.com/jquery/jquery_callback.asp and was quite confused.

There is this code:

$("button").click(function(){
    $("p").hide("slow", function(){
        alert("The paragraph is now hidden");
    });
}); 

Can I check if there is a way to know if the above callback is Synchronous or Asynchronous?

I am guessing it is Synchronous above because it has to wait till the "slow" animation is over before the alert comes up. Is it by default in Javascript or Node.js all callbacks are synchronous unless you do something like setTimeOut or process.nextTick?

the_only_sa
  • 165
  • 1
  • 8
  • 3
    @MercyDude - That link has a lot of awesome information in it that may help answer this question, but it's not a duplicate by itself – Taegost Dec 08 '17 at 18:28
  • 2
    I wouldn't consider this a duplicate at all. The question asked by @Sheen An was based on trying to understand when a Javascript code block is Synchronous or Asynchronous. The question in the link you provided is asking how to retrieve a response from Ajax, which in of itself is Asychronous. – cmpgamer Dec 08 '17 at 18:31

5 Answers5

10

You have several questions here, so I'll try to answer them one by one:

Is it by default in Javascript or Node.js all callbacks are synchronous unless you do something like setTimeOut or process.nextTick?

In the browser you can kinda have this as the rule of thumb: Only setTimeout, setInterval, requests and events are asynchronous. Other built-in callbacks (like Array.prototype.map) are synchronous.

On Node.js it's more complicated: e.g. you can do file reading both synchronously and asynchronously. Then you just need to know that the callback is asynchronous by nature.

Can I check if there is a way to know if the above callback is Synchronous or Asynchronous?

Unfotunately without checking the source code of the method/function you're calling you cannot know if it's synchronous or asynchronous.

I am guessing it is Synchronous above because it has to wait till the "slow" animation is over before the alert comes up.

Exactly. You can find this from jQuery's documentation for .hide method:

complete
Type: Function()
A function to call once the animation is complete, called once per matched element.

jehna1
  • 3,110
  • 1
  • 19
  • 29
  • 1
    This is a proper answer. Nothing but the documentation (or the source code itself)! – Igor Soloydenko Dec 08 '17 at 18:48
  • So can I also ask another question here: what actually determines a function to be synchronous or asynchronous? If I, myself want to write a synchronous function and an asynchronous function, what should I do to make them different? Thanks – Hang Dec 30 '17 at 11:41
  • 1
    @Hang A good read about the subject is the MDN article about JavaScript's Event Loop (https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop). Basically everything in your JS runs synchronously, but you can do asynchronous event listeners (e.g. `setTimeout` is one). Then the script returns only on the next event loop when the specific event is fired – making your code asynchronous. – jehna1 Jan 01 '18 at 13:39
  • @jehna1 thanks a lot for your useful information! I will check it out – Hang Jan 01 '18 at 13:44
3

A callback is a function that will get executed once an Asynchronous process is completed. Let's say we have an object person with the following data.

var person = {
 id: 1034
 name: 'Julio',
 age: 23,
 moneyInBank: 0
}

We want to get the the moneyInBank for this person but we don't have access to that information in our local environment. We need to get it from a database in another server, this could take a while depending internet connection, optimization, etc.

getMoneyInBank(person.id, callback) is going to go over that process and fetch the information we need. If we were to run the next script without the callback.

getMoneyInBank(person.id);
console.log(person.money);

We will get 0 in the output because getMoneyInBank has not finished by the time the log is executed. If we want to make sure we will print meaningful information we need to change our code to something like this.

getMoneyInBank(persion.id, function(){
  console.log(person.money);
});

Using a callback the log only is going to be called when getMoneyInBank finishes.

Julio Ojeda
  • 767
  • 1
  • 6
  • 24
  • Thank you for answering! Can I check, is getMoneyInBank(person.id) sync or async? Because if its sync, does it mean it is operating in the current stack and it will block the operation? And if its sync - we will wait for the operation to complete, and in fact, we will not get 0 in the output. – the_only_sa Dec 12 '17 at 09:06
  • And another question, to help learning : for getMoneyInBank(persion.id, function(){ console.log(person.money); }); i understand the anonymous function is the callback. It will be executed after getMoneyInBank is completed. getMoneyInBank is in current stack. The anonymous function will be callbacked once the current stack is cleared. Which function is the async function and which is the Sync function (or both are async?)? Is it getMoneyInBank or the anonymous function? – the_only_sa Dec 12 '17 at 09:06
2

You can easily check:

function isSync(func, ...args){
 var isSync = false;
 const res = func(...args, r => isSync = true);
 if(res instanceof Promise) res.then(r => isSync = true);
 return isSync;
}

console.log( isSync([].map.bind([])) );
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1

Short answer: You need to examine the caller and look for async operations.

Long answer:

A callback is a simple pattern by which a function is passed as a parameter to an higher order function and is called back it or further down the stack.

let mySynchronousFunction = () => 'Hello';
let myHigherOrderFunction = aFunc => {
    return (aFunc() || 'Goodbye') + ' world!';
};

As soon as there is an I/O operation that would block the main thread, it instead will "branch out" and continue execution.

If we continue with our previous example, we would observe the following behavior:

let myAsyncFunction = () => {
    return http.get('http://some.document')
       .then(response => console.log(response)
    );
};
myHigherOrderFunction(mySynchronousFunction); // 'Hello world!'
myHigherOrderFunction(myAsyncFunction); // 'Goodbye world!'

What happened here is that the main thread continued all the way until it had to wait for I/O and instead of blocking there, it went to the next instruction and took note of the point at which it needs to go when the I/O operation is no longer blocked.

So the next expression to evaluation in our code is:

return expression

But our expression branched out, as such it returns undefined. So we are left with:

return undefined

This means that our higher order function that was passed an async function got undefined when it called aFunc().

Once the I/O is done, the main thread returns to where it left off which is the function passed to Promise handler then. At this point the execution thread has branched out and is separated from main "thread".

Now for your question

The callback will be synchronous when the higher order function which calls it is calling it synchronously. Inversely if it is called within the context of the execution branch of an asynchronous operation it will be asynchronous.

This mean that you need to examine what the higher order function to which you pass your callback is doing and look for async operations.

In the context of your question let us examine the following code (HOF = Higher order function):

let mySynchronousHOC = aFunc => aFunc('Hello world!');
let myAsyncHOC = aFunc => {
    http.get('http://hello.com')
        .then(response => aFunc('Goodbye world!')
    );
};

myAsyncHOC(msg => {
    console.log(msg);
});

mySynchronousHOC(msg => {
   console.log(msg);
});

The result of which will be:

'Hello world'
'Goodbye world'

Here we know that myAsyncHOC is asynchronous because it does an I/O operation.

oLeduc
  • 313
  • 1
  • 12
  • Can I check for : myAsyncFunction - am I right to guess that "http.get('http://some.document')" portion is called in the current stack (if its called in the current stack, is it Synchronous or Async? ) then the ".then(response => console.log(response)" is the callback? it will be scheduled to be in queue after the current stack is cleared? – the_only_sa Dec 10 '17 at 18:28
  • And another question (perhaps unrelated but just for understanding) : Why is some of the lambda functions having the "return" in them but some of them, it is not required. E.g. mySynchronousFunction vs myHigherOrderFunction. What is the difference with return and no return in using promises? :) – the_only_sa Dec 10 '17 at 18:30
  • Wow!! I really appreciate that you are giving such a detailed answer (and this is my first question on Stackoverflow and it is impressive that the community is giving such detailed answers) – the_only_sa Dec 12 '17 at 09:09
  • http.get() is called in the current stack but causes a branching because it uses an async feature of the language (xhr request). The "then(...)" portion is the branched off portion so the function in "then()" behaves like a callback. It is scheduled indeed but not when the current stack is cleared, it goes back as soon as the I/O operation unblocks. Functions in javascript, whether they are lambda or not does not matter, do not need to use the return statement. When the return statement is omitted then will return "undefined". – oLeduc Dec 13 '17 at 14:34
1

I am not sure "synchronous" and "asynchronous" makes sense in this context. You can talk about sync or async when making ajax requests, which would mean that in a sync request everything else stops until the response is received, while in an asynchronous request something else can happen until the server sends the response.

In your particular case ( https://www.w3schools.com/jquery/jquery_callback.asp ) what happens is this:

  • in the "slow" case a timeout is set and the callback is called when the time is out

  • in the second case a timeout is set for hiding the paragraph but the function is called imediately on the next line, before the time is out

this is not sync/async, it is about event programming

Emil Perhinschi
  • 1,185
  • 11
  • 14