Search code examples
javascriptdeferreddeferred-execution

defer function execution without Promise or any JS library


I am working on a library that will expose 3 methods. All three of these methods depend on another library (lets call it libA) having been loaded and that library loads asynchronously.

I could write the code to expose the methods as soon as the JS file has finished loading but then the user would have to defer execution until libA has finished.

I was hoping to, rather, expose "a version" of those 3 methods immediately while libA continues to load asynchronously in the background. Any calls to those 3 methods would get queued up until libA is done loading. And after libA is done loading those 3 methods would get replaced with the real one and the queue would be processed.

Let's say I have this:

var myLib = (function(){
    // expose 3 functions for the user to use
    return {
        "func1" : function(opts){},
        "func2" : function(opts){},
        "func3" : function(opts){}
    }
})();

This library will be loaded by the user. At the same time libA will also be loaded. It may take longer to load then mine or it may finish before mine starts.

So if the user runs myLib.func1({}) and libA has not finished loading then it should get queued up and then when libA is done it should execute. If, on the other hand, libA has finished loading then it would execute immediately.

My initial thought is to do something like this:

var myLib = (function(){
    // queue the calls
    var queue {
        "func1" : [],
        "func2" : [],
        "func3" : []
    };

    // the "temp" functions that just add them to the queue
    var ret = {
        "func1" : function(opts){ queue.func1.push(opts); },
        "func2" : function(opts){ queue.func2.push(opts); },
        "func3" : function(opts){ queue.func3.push(opts); }
    }

    // this may happen before the user users my library or after
    // if it happens before then the functions will be replaced before the user calls them and they won't need to be queued
    // if it happens after then the functions will get replaced and the queued up ones will be executed
    waitForLibAToFinish(function(){
        ret.funct1 = function(opts){alert("this is the real func1");},
        ret.funct2 = function(opts){alert("this is the real func2");},
        ret.funct3 = function(opts){alert("this is the real func3");},

        // process the queue
        for(var i = 0; i < queue.func1.length; ++i)
        {
            ret.func1(queue.func1[i]);
        }

        // repeat for func2 and func3 queue
    });

    return ret;
})();

But this just seems like a bad way to do it. Plus I'll have to have a queue for each function and call each one. There must be a way to abstract that part out so its more generic for all the methods my library exposes.

I'm open to any ideas/suggestions. I just cannot (for numerous reasons out of my control) use any 3rd party libraries like Promise or JavaScript. And, my code has to work on IE8. Trust me, I hate it more than you do.

===

I'm adding some more context/details.

I know I mention SharePoint but this is not an SP specific question.

I am building a library that offers convenience methods to simplify otherwise complicated tasks in SharePoint. All my library does is call SP libraries. The relevant SP libraries are loaded asynchronously. So one of two things needs to happen:

  • Either the user needs to wait for the relevant SP libraries to finish loading before calling any of the methods in my library
  • Or my library needs to wait for the relevant SP libraries to finish

The function SP offers to let you "queue" up your function until a relevant SP library is loaded is ExecuteOrDelayUntillScriptLoaded.

My library is currently built on the first option. I wanted to simplify the experience for the user so they don't have to check (by way of ExecuteOrDelayUntillScriptLoaded). I could change it to the 2nd way but there are reasons I don't want to.

Instead, what I was hoping to do is include 1 check in my library with ExecuteOrDelayUntillScriptLoaded that would "modify" what my library does. Before the relevant libraries are done loading my library would just queue up the calls. And after it is done loading and ExecuteOrDelayUntillScriptLoaded fires, my code would:

  • Execute everything in the queue
  • Modify each function my library exposes to directly execute and not queue

Solution

  • Don't do the queuing yourself. Leave the library loading and dependency resolution to the user. Just expose a function that instantiates your library, the user may call it when library A is ready and get the module with usable methods back.
    There even already is a standard on how to do that: Asynchronous Module Definition. (You don't need require.js as a third-party library, you can implement the bare essentials yourself)

    If the user wants (needs) to call your library methods before everything is loaded, they can always queue the premature invocations themselves in any manner they want. But usually this should not be necessary.