同步使用getScript

时间:2013-02-08 23:29:32

标签: javascript jquery ajax getscript

我正在编写一个需要广泛使用getScript的引擎。为了便于使用,我已将其推入自己的功能,但现在我需要确保函数本身是同步的。不幸的是,我似乎无法让getScript等到它加载的脚本在继续之前实际完成加载。我甚至尝试在调用之前将jQuery的ajax asynch属性设置为false。我正在考虑使用jQuery的when / done协议,但我似乎无法理解将其置于函数内并使函数本身同步的逻辑。非常感谢任何帮助!

function loadScript(script){
//Unrelated stuff here!!!
$.when(
$.getScript(script,function(){
    //Unrelated stuff here!!!
})).done(function(){
    //Wait until done, then finish function
});
}

循环代码(按要求):

for (var i in divlist){
        switch($("#"+divlist[i]).css({"background-color"})){
            case #FFF:
            loadScript(scriptlist[0],divlist[i]);
            break;
        case #000:
            loadScript(scriptlist[2],divlist[i]);
            break;
        case #333:
            loadScript(scriptlist[3],divlist[i]);
            break;
        case #777:
            loadScript(scriptlist[4],divlist[i]);
            break;
    }
}

8 个答案:

答案 0 :(得分:24)

这对我有用,可能对你有帮助。

$.ajax({
    async: false,
    url: "jui/js/jquery-ui-1.8.20.min.js",
    dataType: "script"
});

基本上,我只是绕过了速记符号并添加到async: false

答案 1 :(得分:11)

正如我所说,使用promise对象链接Ajax调用相对容易。现在,它没有看到为什么脚本必须一个接一个地加载,但你有理由这样做。

首先,如果您只使用不同的参数调用相同的函数,我将删除switch语句。例如。您可以将所有脚本URL放在地图中:

var scripts = {
    '#FFF': '...',
    '#000': '...'
    // etc.
};

您可以通过简单地从传递给.then [docs]的回调中返回另一个承诺来链接承诺。您需要做的就是从承诺或延期对象开始:

var deferred = new $.Deferred();
var promise = deferred.promise();

for (var i in divlist) {
    // we need an immediately invoked function expression to capture
    // the current value of the iteration 
    (function($element) {
        // chaining the promises, 
        // by assigning the new promise to the variable
        // and returning a promise from the callback
        promise = promise.then(function() {
            return loadScript(
                scripts[$element.css("background-color")], 
                $element
            );
        });
    }($('#' + divlist[i])));
}

promise.done(function() {
    // optional: Do something after all scripts have been loaded
});

// Resolve the deferred object and trigger the callbacks
deferred.resolve();

loadScript中,您只需返回从$.getScript返回的承诺或.done返回的承诺:

function loadScript(script_url, $element){
    // Unrelated stuff here!!!

    return $.getScript(script_url).done(function(){
        //  Unrelated stuff here
        // do something with $element after the script loaded.
    });
}

脚本将按循环中的访问顺序调用。请注意,如果divlist是一个数组,那么您真的应该使用普通for循环而不是for...in循环。

答案 2 :(得分:5)

你知道$.getScript accepts一个在加载脚本后同步调用的回调函数吗?

示例:

$.getScript(url,function(){
//do after loading script
});

我还有两个解决方案:pure js一个,一个multiple js load

答案 3 :(得分:3)

尝试这种方式,使用延迟对象创建数组,并使用$ .when和“apply”

var scripts = [
    'src/script1.js',
    'src/script2.js'
];

var queue = scripts.map(function(script) {
    return $.getScript(script);
});

$.when.apply(null, queue).done(function() {
    // Wait until done, then finish function
});

答案 4 :(得分:0)

var getScript = function(url) {
    var s = document.createElement('script');
    s.async = true;
    s.src = url;
    var to = document.getElementsByTagName('script')[0];
    to.parentNode.insertBefore(s, to);
};

答案 5 :(得分:0)

@Felix Kling的回答是一个不错的开始。但是,我发现如果要“功能化”,返回的.done()末尾的附加.getScripts()会有一个小问题。您需要循环中链式.getScript()迭代的最后一个承诺。这是他的解决方案的修改版(谢谢您,顺便说一句)。

插件:

(function ($) {
    var fetched = new function () {
            this.scripts = [];
            this.set = [];

            this.exists = function (url) {
                var exists = false;

                $.each(this.set, function (index, value) {
                    if ((url || '') === value) {
                        exists = true;

                        return false;
                    }
                });

                return exists;
            };

            this.buildScriptList = function () {
                var that = this;

                that.set = [];

                $('script').each(function () {
                    var src = $(this).attr('src') || false;

                    if (src) {
                        that.set.push(src);
                    }
                });

                $.merge(this.set, this.scripts);

                return this;
            };
        },
        getScript = $.getScript;

    $.getScript = function () {
        var url = arguments[0] || '';

        if (fetched.buildScriptList().exists(url)) {
            return $.Deferred().resolve();
        }

        return getScript
            .apply($, arguments)
            .done(function () {
                fetched.scripts.push(url);
            });
    };

    $.extend({
        getScripts: function (urls, cache) {
            if (typeof urls === 'undefined') {
                throw new Error('Invalid URL(s) given.');
            }

            var deferred = $.Deferred(),
                promise = deferred.promise(),
                last = $.Deferred().resolve();

            if (!$.isArray(urls)) {
                urls = [urls];
            }

            $.each(urls, function (index) {
                promise = promise.then(function () {
                    last = $.getScript(urls[index]);

                    return last;
                });
            });

            if (Boolean(cache || false) && !Boolean($.ajaxSetup().cache || false)) {
                $.ajaxSetup({cache: true});

                promise.done(function () {
                    $.ajaxSetup({cache: false});
                });
            }

            deferred.resolve();

            return last;
        }
    });
})($);

您可以忽略获取的功能(我实现了该功能以减少潜在的冗余调用-这就是我劫持.getScript()的原因),并查看变量last.getScripts()方法内的位置。它默认为解析的延迟对象,因此,如果urls数组为空,则将其传递给返回的结果,以将外部.done()附加到该结果。否则,将不可避免地为链式.getScript()调用分配最后一个诺言对象,从而确保一切都将从函数外部保持同步。

如果您先解决了最初创建的延迟对象,然后再将其返回给调用者(这是根据jQuery's official documentation应该执行的操作),则无法将其恢复。

示例:

function loadStuff(data) {
    var version = {
        'accounting': '1.2.3',
        'vue': '1.2.3',
        'vueChart': '1.2.3'
    };

    $.getScripts([
        'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/' + version.accounting + '/accounting.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/vue/' + version.vue + '/vue.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/vue-chartjs/' + version.vueChart + '/vue-chartjs.min.js'
    ], true)
        .done(function () {
            // do stuff
        })
        .fail(function () {
            throw new Error('There was a problem loading dependencies.');
        });
}

答案 6 :(得分:-1)

只需创建一个脚本节点,将其src属性设置为您要加载的JS,然后将其附加到头部:

var myScript = document.createElement('script');
myScript.src = "thesource.js";
document.head.appendChild(myScript);

答案 7 :(得分:-1)

这就是我的工作

function loadJsFile(filename) {
    $.ajaxSetup({
        cache: true
    });

    var dloadJs = new $.Deferred();
    $.when(dloadJs).done(function () {
        $.ajaxSetup({
            cache: false
        });
    });

    dloadJs.resolve(
         $.getScript(filename, function () { })
    );
}