You Dont Know JS (ydkjs): Async & Performance - Callbacks [unable to understand function asyncify]

First here is code -
From the book -

What if you don’t know whether the API in question will always execute async? You could invent a utility like this asyncify(…) proof-of-concept:

function asyncify(fn) {
    var orig_fn = fn,
        intv = setTimeout( function(){
            intv = null;
            if (fn) fn();
        }, 0 )
    ;

    fn = null;

    return function() {
        // firing too quickly, before `intv` timer has fired to
        // indicate async turn has passed?
        if (intv) {
            fn = orig_fn.bind.apply(
                orig_fn,
                // add the wrapper's `this` to the `bind(..)`
                // call parameters, as well as currying any
                // passed in parameters
                [this].concat( [].slice.call( arguments ) )
            );
        }
        // already async
        else {
            // invoke original function
            orig_fn.apply( this, arguments );
        }
    };
}

You use asyncify(…) like this:

function result(data) {
    console.log( a );
}

var a = 0;

ajax( "..pre-cached-url..", asyncify( result ) );
a++;

Now my doubt -

ajax request will be made and the return value of asyncify(result) will be used as callback for ajax request.
Now let’s see asyncify function-
What I see is two cases -

  1. callback functiion inside intv = setTimeout ... is put in the eventloop queue before the return function from asyncify()
  2. return function from asyncify() is put in eventloop queue before intv = setTimeout ...

Let’s see case1-
callback functiion inside intv = setTimeout ... will be executed before the return function from asyncify() in which case

            // invoke original function
            orig_fn.apply( this, arguments );
        }```
this part will execte and I am fine with this.

***case2-***
2) return function from `asyncify()` is put in eventloop queue before  `intv = setTimeout ...` 
I am unable to understand in which scenario and how this is going to happen?

Hi @Faizahmadfaiz

This is a complex interesting problem. The problem posted by the author is:

What if you don’t know whether the API in question will always execute async? You could invent a utility like this asyncify(…) proof-of-concept

The following is my interpretation (I haven’t read the book yet…):


First, the name of the function already says what the function will do: it will render any non-async data into async.

What the author I think is doing is assigning a async attribute/method to any sync function.

But in order to recognise if the url passed to ajax is sync, it runs it first, at time = 0.

intv = setTimeout(function(){<run the function>}, ZERO-TIME)

If any value for intv is captured in the next function, then the function was sync. Only an async function will render intv = null in this exercise because it won’t run immediately: it will wait. He explain that in the following comments:

// firing too quickly, before intv timer has fired to
// indicate async turn has passed?

Then it comes a the anonymous functionality in

return function(){....}

This function is apparently a callback of a CLOSURE (there are many references about it, you could read perhaps this one too: https://medium.freecodecamp.com/lets-learn-javascript-closures-66feb44f6a44#.igdmafc5a).

EDIT: you can follow also an interesting discussion focused on function SCOPES related to the same book just here in the forum: You Don't Know JavaScript, Scope and Closures Chapter 5 Question - #7 by brianrodriguez - The freeCodeCamp Forum

The author passes any function into the event loop with its corresponding arguments. He uses this because the author is considering the current scope of the orig_fn function. For the sync though, a binding is required because you are likely assigning an attribute/method to a functionality to make it async. Let’s read well this other interesting part:

orig_fn.BIND.APPLY(orig_fn, [THIS].CONCAT( .... ) )

Let’s compares with what would happen if the function is captured as asyn. What would pass?

orig_fn.APPLY( THIS, ARGUMENTS)

The author is using this trick to bind to the sync function the capacity to behave as the passed async function by AJAX. Specifically, the sync function will run later.

Let’s see what happens.

Remember that

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
(Function.prototype.bind() - JavaScript | MDN)

So what this means? It means that it is binding to orig_fn a function to ITSELF with the attributes attached, BUT NOT RUN. It will run when the callback function runs (this is WOW!). The attributes passed to the sync orig_fn are obtained from the orig_fn itself by getting them from this.

Brilliant.

Now what happens with the async? Well: the callback function runs, which runs the async with the corresponding arguments which is like running an async function in the first place. Nothing happens. If ready, then it will render the data. If error, it will throw an error. Just like any other async function.

You said something about event loop. Well, it is the WHOLE asyncify function that is passed by AJAX to the event loop, not just setTimeout(…):

ajax( "..pre-cached-url..", ASYNCIFY( result ) );

I haven’t read that book… I think I should…

Please correct me if I am wrong? I am not a programmer myself so this is my interpretation based on what I have learnt here. I hope other people will comment…

Hope this helped?

2 Likes