了解封:构造元函数,排队功能整合在一起(Understanding closures: Constr

2019-11-01 21:10发布

在解决这个问题方面,我有我只是在这里完成了一个完全可行的解决方案:

// synchronous dynamic script loading. 
// takes an array of js url's to be loaded in that specific order. 
// assembles an array of functions that are referenced more directly rather than 
// using only nested closures. I couldn't get it going with the closures and gave up on it. 

function js_load(resources, cb_done) {
    var cb_list = []; // this is not space optimal but nobody gives a damn 
    array_each(resources, function(r, i) {
        cb_list[i] = function() {
            var x = document.body.appendChild(document.createElement('script'));
            x.src = r;
            console.log("loading "+r);
            x.onload = function() { 
                console.log("js_load: loaded "+r); 
                if (i === resources.length-1) {
                    cb_done();
                } else {
                    cb_list[i+1]();
                }
            }; 
        };
    });
    cb_list[0]();
}

我这个完全满意,因为它做什么,我现在想要的,并可能是更容易比我的第一种方法,如果成功了,会一直进行调试。

但我不能克服就是为什么我永远无法得到它的工作。

它看起来是这样的。

function js_load(resources, cb_done) {
    var cur_cont = cb_done;
    // So this is an iterative approach that makes a nested "function stack" where 
    // the inner functions are hidden inside the closures. 
    array_each_reverse(resources, function(r) {
        // the stack of callbacks must be assembled in reverse order
        var tmp_f = function() {
            var x = document.body.appendChild(document.createElement('script'));
            x.src = r;
            console.log("loading "+r);
            x.onload = function() { console.log("js_load: loaded "+r); cur_cont(); }; // TODO: get rid of this function creation once we know it works right 
        };
        cur_cont = tmp_f; // Trying here to not make the function recursive. We're generating a closure with it inside. Doesn't seem to have worked :(
    });
    cur_cont();
}

它一直试图调用自身无限循环,除其他奇怪的东西,它真的很难识别功能的功能是与在它包含哪些功能,在调试过程中。

我没有深入到代码,但似乎jQuery.queue也实施了类似的机制,以我的工作一个(使用数组来跟踪延续的队列),而不是只用瓶盖。

我的问题是:是否有可能建立一个可以接受一个函数作为参数一个Javascript功能,并与其他功能列表提升它,通过建立封装函数它创建自己封闭?

这是真的很难形容。 但我敢肯定有人有它合适的理论支持的数学术语。

PS通过引用上面的代码是这些例程

// iterates through array (which as you know is a hash), via a for loop over integers
// f receives args (value, index)
function array_each(arr, f) {
    var l = arr.length; // will die if you modify the array in the loop function. BEWARE
    for (var i=0; i<l; ++i) {
        f(arr[i], i);
    }
}

function array_each_reverse(arr, f) {
    var l = arr.length; // will die if you modify the array in the loop function. BEWARE
    for (var i=l-1; i>=0; --i) {
        f(arr[i], i);
    }
}

Answer 1:

问题是如何你设定的值cur_cont为你做的每一个新的功能,并呼吁cur_contonload回调。 当您进行封样tmp_f ,像任何自由变量cur_cont 不是 “冻结”到它们的当前值。 如果cur_cont在一切都变了,从内到任何参考tmp_f将引用新的,更新的价值。 当你在不断变化cur_cont成为新tmp_f你刚才所作的功能,参考其它功能都将丢失。 然后,当cur_cont执行和完成, cur_cont再次调用。 这正是刚刚结束执行相同的功能 - 因此无限循环!

在这种情况,你需要保持一个封闭的内部自由变量的值,最容易做的事情就是让一个新的功能,并呼吁与你想保留的价值。 通过调用这个新功能,只是针对运行,这将让你需要的值,创建一个新的变量。

function js_load(resources, cb_done) {
    var cur_cont = cb_done;
    array_each_reverse(resources, function(r) {
        // the stack of callbacks must be assembled in reverse order

        // Make a new function, and pass the current value of the `cur_cont`
        // variable to it, so we have the correct value in later executions.
        // Within this function, use `done` instead of `cur_cont`;
        cur_cont = (function(done) {

            // Make a new function that calls `done` when it is finished, and return it.
            // This function will become the new `cur_cont`.
            return function() {

                var x = document.body.appendChild(document.createElement('script'));
                x.src = r;
                console.log("loading "+r);
                x.onload = function() {
                    console.log("js_load: loaded "+r);
                    done();
                };
            };
        })(cur_cont);

    });

    // Start executing the function chain
    cur_cont();
}

编辑:其实,这可制成即使使用简单的Array.reduce功能。 从概念上讲,你正在服用的数组,并产生从该阵列中的单个功能,和生成的每个连续的功能应该是依赖于所产生的最后一个函数。 这是减少旨在​​帮助解决的问题:

function js_load(resources, done) {
    var queue = resources.reduceRight(function(done, r) {
        return function() {
            var x = document.body.appendChild(document.createElement('script'));
            x.src = r;
            console.log("loading "+r);
            x.onload = function() {
                console.log("js_load: loaded "+r);
                done();
            };
        };
    }, done);

    queue();
};

需要注意的是reducereduceRight不适用于旧的浏览器(<= IE8)。 一个JavaScript实现可以在上找到MDN页面 。



文章来源: Understanding closures: Constructing a meta-function that queues functions together