如何等待动态加载的脚本在javascript中完全执行?

时间:2018-11-09 06:29:50

标签: javascript jquery ajax promise

在javascript中,我加载了几个脚本,然后又想运行一个函数。问题是,我的承诺为时过早。它在下载每个文件后运行,但是我需要它等待它们全部添加到DOM中并完全执行。

(function() {

    function getFile(path) {
        return $.get(path, function (data) {
            $("body").append(data);
        });
    }

    $.when.apply($, [
        // load all the individual components
        "components/once/ti-snackbar/ti-snackbar.html",
        "components/once/ti-not-supported/ti-not-supported.html",
        "components/once/ti-drawer/ti-drawer.html",
        "components/widgets/ti-company-table-row/ti-company-table-row.html",
        "components/widgets/ti-chip-set/ti-chip-set.html",
        "components/widgets/ti-list/ti-list.html",
        "components/widgets/ti-user-card/ti-user-card.html",
        "components/widgets/ti-tabs/ti-tabs.html",
        "components/widgets/ti-data-table/ti-data-table.html",
        "components/forms/ti-new-company-form/ti-new-company-form.html",
        "components/forms/ti-edit-company-form/ti-edit-company-form.html",
        "components/pages/ti-page-inquire/ti-page-inquire.html",
        "components/pages/ti-page-companies/ti-page-companies.html",
        "components/pages/ti-page-report/ti-page-report.html",
        "components/pages/ti-page-admins/ti-page-admins.html",
        "components/pages/ti-page-contacts/ti-page-contacts.html",
        "components/pages/ti-page-policy/ti-page-policy.html",
        "components/pages/ti-page-manual/ti-page-manual.html",
        "components/pages/ti-page-404/ti-page-404.html",
        "components/tabs/ti-tab-name/ti-tab-name.html",
        "components/tabs/ti-tab-tags/ti-tab-tags.html",
        "components/tabs/ti-tab-status/ti-tab-status.html",   
        "components/tabs/ti-tab-restriction/ti-tab-restriction.html",     
        "components/tabs/ti-tab-other/ti-tab-other.html"   
    ].map(getFile)).then(function() {
        // render the full app after all components load
        getFile("components/once/ti-app/ti-app.html");
    });
})();

我该如何解决?

注意:每个html文件都有一个<script><template>

谢谢

2 个答案:

答案 0 :(得分:1)

我看到此代码可能有几个问题:

  1. 您并没有强迫您的$.get()调用按顺序完成,因此您可以获得可变的完成顺序,并且事情可能会以不同的顺序附加到主体上(如果重要的话)。

  2. 您正在使用promise和回调的混合使用,这可能会使准确地排序事物变得困难。通常,不要混用promise和回调。如果您将诺言放在一个地方,请在各处使用它们(必要时将回调转换为诺言)。

  3. 您说您“想在之后运行一个函数”,但是您没有解释要在哪里放置该函数。要等待所有承诺,它必须在.then()处理程序中。

这是清理这些内容的实现:

(function() {

    function getFile(path) {
        return $.get(path);
    }

    function append(data) {
        $("body").append(data);
    }

    var resources = [
        "components/once/ti-snackbar/ti-snackbar.html",
        "components/once/ti-not-supported/ti-not-supported.html",
        "components/once/ti-drawer/ti-drawer.html",
        "components/widgets/ti-company-table-row/ti-company-table-row.html",
        "components/widgets/ti-chip-set/ti-chip-set.html",
        "components/widgets/ti-list/ti-list.html",
        "components/widgets/ti-user-card/ti-user-card.html",
        "components/widgets/ti-tabs/ti-tabs.html",
        "components/widgets/ti-data-table/ti-data-table.html",
        "components/forms/ti-new-company-form/ti-new-company-form.html",
        "components/forms/ti-edit-company-form/ti-edit-company-form.html",
        "components/pages/ti-page-inquire/ti-page-inquire.html",
        "components/pages/ti-page-companies/ti-page-companies.html",
        "components/pages/ti-page-report/ti-page-report.html",
        "components/pages/ti-page-admins/ti-page-admins.html",
        "components/pages/ti-page-contacts/ti-page-contacts.html",
        "components/pages/ti-page-policy/ti-page-policy.html",
        "components/pages/ti-page-manual/ti-page-manual.html",
        "components/pages/ti-page-404/ti-page-404.html",
        "components/tabs/ti-tab-name/ti-tab-name.html",
        "components/tabs/ti-tab-tags/ti-tab-tags.html",
        "components/tabs/ti-tab-status/ti-tab-status.html",   
        "components/tabs/ti-tab-restriction/ti-tab-restriction.html",     
        "components/tabs/ti-tab-other/ti-tab-other.html"   
    ];

    return Promise.all(resources.map(getFile)).then(function(data) {
        // append all items to the body in order now that they are all retrieved
        data.forEach(append);
    }).then(function() {
        // now that everything else is in place, load and append 
        // the part that uses those scripts and templates
        return getFile("components/once/ti-app/ti-app.html").then(append);
    }).catch(function(err) {
        // handle error here
        console.log(err);
        throw err;    // propagate error
    });
})().then(function() {
    // everything loaded here for code outside the IIFE here to know when it's all done
}).catch(function(err) {
    // error occurred here for code outside the IIFE here to know there was an error
});

如果您希望IIFE以外的代码能够知道何时完成或发生错误,则最后一个.then().catch()是可选的。

已修改的事物和推理:

  1. 首先加载所有资源,然后以可预测的顺序附加所有资源,从而使您具有相互依赖关系或可以依赖于先前依赖关系的任何脚本初始化。以前,没有确定脚本附加的顺序。

  2. ti-app.html将不会被加载和附加,直到所有其他脚本都被加载和附加

  3. 将脚本数组的声明移到了主代码流之外,只是为了提高代码流的可读性。

  4. 添加了错误检测

  5. 在完成所有加载或出现错误时,可以提供两个位置,一个位于IIFE内,另一个位于IIFE以外(取决于您的需要)。

答案 1 :(得分:0)

这可能很有用:https://css-tricks.com/snippets/javascript/async-script-loader-with-callback/

var Loader = function () { }
Loader.prototype = {
    require: function (scripts, callback) {
        this.loadCount      = 0;
        this.totalRequired  = scripts.length;
        this.callback       = callback;

    for (var i = 0; i < scripts.length; i++) {
        this.writeScript(scripts[i]);
    }
},
loaded: function (evt) {
    this.loadCount++;

    if (this.loadCount == this.totalRequired && typeof this.callback == 'function') this.callback.call();
},
writeScript: function (src) {
    var self = this;
    var s = document.createElement('script');
    s.type = "text/javascript";
    s.async = true;
    s.src = src;
    s.addEventListener('load', function (e) { self.loaded(e); }, false);
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(s);
}

用法:

var l = new Loader();
l.require([
"example-script-1.js",
"example-script-2.js"], 
function() {
    // Callback
    console.log('All Scripts Loaded');
    // call your other script here
});