使用script_queue进行JS函数时的执行顺序

时间:2014-02-20 23:31:46

标签: javascript jquery

在我们的工作场所,我们在site.master页面中定义了一个脚本队列

<script>
    // append functions to this array that will be executed after js dependencies have loaded
    var script_queue = [];
</script>

然后我们将javascript函数推送到此script_queue来执行它们。我遇到了一个问题,比如我有两个功能

<script type="text/javascript">
// THIS IS FUNCTION 1
       script_queue.push(function() {

           // set the width of the thumbnail list to the sum of all the li widths
           var thumbsWidth = 0;
           $('#oneClipPlaylist li').each(func
     …
}
</script>


  script_queue.push(function() {
     // THIS IS FUNCTION 2
        var allInputs = $('fieldset.categories input');
        var categoryInputs = $('fieldset.categories input').not('#categoryAll');
        var categoryAllInput = $('#categoryAll');

        allInputs.click(function() {

            var checkbox = $(this);

这是队列的处理方式:

<script> 
    (function () { 
        for (var i in script_queue) { 
            script_queue[i](); 
        } 
    } ());
</script>

如何确保在功能2之前执行功能1?因为我遇到了我的功能2在功能1之前执行并且结果不正确的问题

2 个答案:

答案 0 :(得分:1)

我很久以前就已经实现了类似的系统,远在很远的地方工作:) 我们的目的是在需要这些依赖项的其他脚本之前加载依赖项。例如,如果您以这种方式加载jQuery,那么使用jQuery的任何其他脚本显然必须在加载jQuery之后才执行。任何自定义JS对象都是如此。

一些注意事项:

你的代码将在for循环中以正确的顺序执行。所以,如果没有发生,那么它应该是

  1. 如何向队列添加功能。它们可能不会按照您的想法添加。这将是一个原因;

  2. 使用Ajax回调或其他异步代码的函数,例如动态加载外部JS文件。函数可能会执行并等待结果,但在等待时,其他函数将在for循环中执行。

  3. 第一个很容易检查 - 只需在处理函数之前验证函数的顺序是否正常,然后查看它是否按正确的顺序排列,然后检查应用程序代码以了解发生这种情况的原因。

    最有可能的是,这是由于#2 - 异步调用加载JS文件和/或Ajax调用; (要查看如何/为什么它不按顺序工作的示例,请参阅答案的底部)

    一种可能的解决方案:各种脚本加载管理器

    相当简单,我们使用此对象将脚本添加到队列中,特别考虑了Ajax。脚本可以全部依赖于任何内容或其他脚本。当我们处理队列时,只会立即执行没有依赖关系的脚本。

    然后,当脚本完成时,将执行任何相关脚本。唯一特殊情况是Ajax,只需要进行微小的更改,即向contextsettings调用的jQuery.ajax()对象添加jQuery.ajaxComplete()属性,并注册全局context<script type="text/javascript"> // Let's create global $jsload object to handle queueing of JS scripts var $jsload = (function () { // Let's make the internals private var scriptQueue = {}; var dependencies = {}; var enqueue = function (key, scriptFunc, dependencyKey, isAjax) { scriptQueue[key] = { dependencyKey: dependencyKey, func: function () { scriptFunc(); if (!isAjax) scriptCallBack(key); } }; addDependencyItem(key, dependencyKey); } var addDependencyItem = function (key, dependencyKey) { if (null == dependencyKey) return; // Check to add to dependencies if (null == dependencies[dependencyKey] || 'undefined' == dependencies[dependencyKey]) dependencies[dependencyKey] = {}; // add this script to dependent scripts dependencies[dependencyKey][key] = { isCompleted: false }; }; var checkDependency = function (key, dependencyKey) { var obj = dependencies[scriptQueue[key].dependencyKey]; if (null != obj && !obj.isCompleted) return false; return true; }; var scriptCallBack = function (key) { // Called when a script has finished; now ok to process dependencies if (null != dependencies[key]) { for (var itemKey in dependencies[key]) { scriptQueue[itemKey].func(); dependencies[key][itemKey].isCompleted = true; } } }; // The jsLoaderWithDependency object executes dependent scripts in the correct order // The only callable public methods are queue, ajax, and processQueue var jsLoaderWithDependency = { queue: function (key, scriptFunc, dependencyKey) { enqueue(key, scriptFunc, dependencyKey, false) }, ajax: function (key, scriptFunc, dependencyKey) { enqueue(key, scriptFunc, dependencyKey, true) }, processQueue: function () { for (var key in scriptQueue) { if (checkDependency(key)) { scriptQueue[key].func(); } } } } // This handler will execute at end of all Ajax requests; // You can instead meake separate success/error handlers, // for example, not to execute dependency scripts on error // yet still show a message and/or log the error, etc. $(document).ready(function () { $(document).ajaxComplete(function (event, xhr, settings) { scriptCallBack(settings.context); }); }); return jsLoaderWithDependency; })(); // Auto-execute self and init </script> 属性的值应设置为脚本键(即“Script0”)。

    $ jsload对象:

    <script type="text/javascript">
    
    // Usage and test code
    $jsload.ajax(
        "Script0",
        function () {
            $.ajax({
                // This is the only small change needed for dependency callback
                context: "Script0", 
    
                // Standard ajax settings
                url: "",
                data: "ho ho ho",
                dataType: "jsonp",
                jsonp: "jsonp",
    
                success: function (response, textS, xhr) {
                    console.log("Script 0 ( Ajax ) (no dependency) success");
                },
                error: function (xmlHttpRequest, textStatus, errorThrown) {
                    console.log("Script 0 ( Ajax ) (no dependency) error");
                }
            });
            console.log("Script 0 ( Ajax ) (no dependency) start");
        },
        null
    );
    $jsload.queue(
        "Script1",
        function () { console.log("Script 1 (dependency on Script 0, ajax callback)"); },
        "Script0"
    );
    $jsload.queue(
        "Script2",
        function () { console.log("Script 2 (depends on Script 3)"); },
        "Script3"
    );
    $jsload.queue(
        "Script3",
        function () { setTimeout(console.log("Script 3 Timeout (depends on Script 1)"), 1000); },
        "Script1"
    );
    $jsload.queue(
        "Script4",
        function () { console.log("Script 4 (no dependency)");},
        null
    );
    
    $jsload.processQueue();
    
    
    </script>
    

    如何排队和执行功能的一些使用示例:

        // Adding basic functions to queue
        script_queue.push(function () { console.log(1); });        
        script_queue.push(function () { console.log(2); });
        script_queue.push(function () { console.log(3); });
        script_queue.push(function () { console.log(4); });
        script_queue.push(function () { console.log(5); });
    
        // Let's do some Ajax!
        script_queue.push(function () {
            $.ajax({
                type: "GET", url: "http://otherdomain.com/somePage.html",
                data: "ho ho ho", dataType: "jsonp", jsonp: "jsonp",
    
                success: function (response, textS, xhr) {
                    console.log("6 ajax finished success")
                },
                error: function (xmlHttpRequest, textStatus, errorThrown) {
                    console.log("6 ajax finished error")
                }
            });
            console.log("6 ajax start");
        });
        // Let's throw in a timeout
        script_queue.push(function () {
            window.setTimeout(function () { console.log("7 with timeout") }, 1000);
        });
        script_queue.push(function () { console.log(8); });
        script_queue.push(function () { console.log(9); });
        script_queue.push(function () { console.log(10); });
    
        // Process the funcs
        (function () { 
            for (var i in script_queue) { 
                script_queue[i](); 
            } 
        } ());
    
    </script>
    

    结果:

    enter image description here

    这实际上是一个基本的开始,当然可以改进它来处理动态脚本加载(使用加载的事件)和其他应用程序需求。但我认为这对于这种功能的框架来说是一个不错的开端。


    没有依赖关系的基本代码示例及其中断的一些场景:

    这是一个简单的脚本处理示例,除了超时和异步调用:              //将函数附加到此数组,该数组将在加载js依赖项后执行         var script_queue = [];

    {{1}}

    并且,控制台的结果:

    enter image description here

    正如您所看到的,大多数函数按顺序执行 - Ajax以正确的顺序启动 - 但是当执行回调并且超时完成时,所有其他函数都已经处理完毕。

    依赖关系管理器是解决此问题的一种方法。

    希望这会有所帮助,并为您提供一些想法!


答案 1 :(得分:0)

命名第二个函数并且不将其排队,然后在第一个放入队列的函数的末尾调用第二个函数。

<script type="text/javascript">
// THIS IS FUNCTION 1
       script_queue.push(function() {

           // set the width of the thumbnail list to the sum of all the li widths
           var thumbsWidth = 0;
           $('#oneClipPlaylist li').each(func
     …
    secondFunc();
}

function secondFunc() {
// THIS IS FUNCTION 2
        var allInputs = $('fieldset.categories input');
        var categoryInputs = $('fieldset.categories input').not('#categoryAll');
        var categoryAllInput = $('#categoryAll');

        allInputs.click(function() {

            var checkbox = $(this);

    ...
}
</script>