Javascript - synchronizing after asynchronous calls

前端 未结 6 1634
北恋
北恋 2021-02-04 02:08

I have a Javascript object that requires 2 calls out to an external server to build its contents and do anything meaningful. The object is built such that instantiating an inst

6条回答
  •  春和景丽
    2021-02-04 02:48

    Unless you're willing to serialize the AJAX there is no other way that I can think of to do what you're proposing. That being said, I think what you have is fairly good, but you might want to clean up the structure a bit to not litter the object you're creating with initialization data.

    Here is a function that might help you:

    function gate(fn, number_of_calls_before_opening) {
        return function() {
            arguments.callee._call_count = (arguments.callee._call_count || 0) + 1;
            if (arguments.callee._call_count >= number_of_calls_before_opening)
                fn.apply(null, arguments);
        };
    }
    

    This function is what's known as a higher-order function - a function that takes functions as arguments. This particular function returns a function that calls the passed function when it has been called number_of_calls_before_opening times. For example:

    var f = gate(function(arg) { alert(arg); }, 2);
    f('hello');
    f('world'); // An alert will popup for this call.
    

    You could make use of this as your callback method:

    foo.bar = function() {
        var callback = gate(this.method, 2);
        sendAjax(new Request(), callback);
        sendAjax(new Request(), callback);
    }
    

    The second callback, whichever it is will ensure that method is called. But this leads to another problem: the gate function calls the passed function without any context, meaning this will refer to the global object, not the object that you are constructing. There are several ways to get around this: You can either close-over this by aliasing it to me or self. Or you can create another higher order function that does just that.

    Here's what the first case would look like:

    foo.bar = function() {
        var me = this;        
        var callback = gate(function(a,b,c) { me.method(a,b,c); }, 2);
    
        sendAjax(new Request(), callback);
        sendAjax(new Request(), callback);
    }
    

    In the latter case, the other higher order function would be something like the following:

    function bind_context(context, fn) {
        return function() {
            return fn.apply(context, arguments);
        };
    }
    

    This function returns a function that calls the passed function in the passed context. An example of it would be as follows:

    var obj = {};
    var func = function(name) { this.name = name; };
    var method = bind_context(obj, func);
    method('Your Name!');
    alert(obj.name); // Your Name!
    

    To put it in perspective, your code would look as follows:

    foo.bar = function() {
        var callback = gate(bind_context(this, this.method), 2);
    
        sendAjax(new Request(), callback);
        sendAjax(new Request(), callback);
    }
    

    In any case, once you've made these refactorings you will have cleared up the object being constructed of all its members that are only needed for initialization.

提交回复
热议问题