23

我正在编写一个需要广泛使用 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;
    }
}
4

8 回答 8

31

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

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

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

于 2013-07-26T16:22:44.557 回答
11

正如我所说,将Ajax 调用与promise 对象链接起来相对容易。现在,它不明白为什么必须一个接一个地加载脚本,但你会有理由这样做。

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

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

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

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循环。

于 2013-02-09T02:34:45.850 回答
6

你知道$.getScript 接受脚本加载后同步调用的回调函数吗?

例子:

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

我还有 2 个解决方案:一个纯 js 一个和一个用于多个 js load

于 2014-10-27T13:13:47.153 回答
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
});
于 2013-02-08T23:46:29.877 回答
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);
};
于 2013-02-09T00:01:11.170 回答
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;
        }
    });
})($);

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

如果您在将其返回给调用者之前将其解析,则返回最初创建的延迟对象将不起作用(这是您应该按照jQuery 的官方文档执行的操作)。

例子:

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.');
        });
}
于 2018-10-19T12:59:58.203 回答
-1

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

var myScript = document.createElement('script');
myScript.src = "thesource.js";
document.head.appendChild(myScript);
于 2013-02-08T23:31:59.507 回答
-1

这就是我所做的

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

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

    dloadJs.resolve(
         $.getScript(filename, function () { })
    );
}
于 2016-03-30T13:40:38.293 回答