提问



JavaScript中有类似@import的内容,允许您在另一个JavaScript文件中包含JavaScript文件吗?

最佳参考


旧版本的JavaScript没有导入,包含或要求,因此开发了许多不同的方法来解决这个问题。


但是最新版本的JavaScript有像ES6模块这样的标准来导入模块,尽管大多数浏览器都不支持。许多使用浏览器应用程序模块的人使用构建和/或转换工具来使用带有模块等功能的新语法变得切实可行。[119] [120] [121]


ES6模块



请注意,目前,对ES6模块的浏览器支持并不是特别好,但它正在进行中。根据StackOverflow的回答,Chrome 61,Firefox 54(about:config中的dom.moduleScripts.enabled设置之后)和MS Edge 16支持它们,只有Safari 10.1提供不带标记的支持。


因此,您目前仍需要使用构建和/或转换工具来运行有效的JavaScript,而无需用户使用这些浏览器版本或启用任何标志。


一旦ES6模块很常见,以下是您使用它们的方法:


// module.js
export function hello() {
  return "Hello";
}


// main.js
import {hello} from 'module'; // or './module'
let val = hello(); // val is "Hello";


Node.js需要



Node.js目前正在使用module.exports/require系统。如果需要import语法,可以使用babel进行转换。 [123]


// mymodule.js
module.exports = {
   hello: function() {
      return "Hello";
   }
}


// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"   


JavaScript还有其他方法可以在不需要预处理的浏览器中包含外部JavaScript内容。


AJAX加载



您可以使用AJAX调用加载其他脚本,然后使用eval运行它。这是最简单的方法,但由于JavaScript沙箱安全模型,它仅限于您的域。使用eval也打开了通往错误,黑客和安全问题的大门。


jQuery加载



jQuery库在一行中提供加载功能:[124] [125]


$.getScript("my_lovely_script.js", function() {
   alert("Script loaded but not necessarily executed.");
});


动态脚本加载



您可以将带有脚本URL的脚本标记添加到HTML中。为了避免jQuery的开销,这是一个理想的解决方案。


该脚本甚至可以驻留在不同的服务器上。此外,浏览器评估代码。 <script>标签可以注入网页<head>,也可以在结束</body>标签之前插入。


以下是一个如何工作的示例:


function dynamicallyLoadScript(url) {
    var script = document.createElement("script"); // Make a script DOM node
    script.src = url; // Set it's src to the provided URL

    document.head.appendChild(script); // Add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}


此函数将新的<script>标记添加到页面的head部分的末尾,其中src属性设置为作为第一个参数赋予函数的URL。


这两个解决方案都在JavaScript疯狂:动态脚本加载中进行了讨论和说明。[126]


检测脚本何时执行



现在,您必须了解一个大问题。这样做意味着您远程加载代码。现代Web浏览器将加载文件并继续执行当前脚本,因为它们异步加载所有内容以提高性能。 (这适用于jQuery方法和手动动态脚本加载方法。)


这意味着如果您直接使用这些技巧,在您要求加载之后,您将无法在下一行使用新加载的代码,因为它仍将加载。


例如:my_lovely_script.js包含MySuperObject:


var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined


然后重新加载页面点击 F5 。它的工作原理!混乱...


那该怎么办呢?


好吧,你可以在我给你的链接中使用作者建议的黑客。总之,对于匆忙的人,他在加载脚本时使用事件来运行回调函数。因此,您可以使用远程库将所有代码放在回调函数中。例如:


function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}


然后在lambda函数中加载脚本后编写要使用的代码:[127]


var myPrettyCode = function() {
   // Here, do whatever you want
};


然后你运行所有:


loadScript("my_lovely_script.js", myPrettyCode);


请注意,脚本可以在DOM加载之后或之前执行,具体取决于浏览器以及是否包含行script.async = false;。关于Javascript加载的一篇很棒的文章对此进行了讨论。[128]


源代码合并/预处理



正如在本答案的顶部所提到的,许多开发人员现在在他们的项目中使用像WebPack,Babel或Gulp这样的构建/转换工具,允许他们更好地使用新的语法和支持模块,组合文件,缩小等。

其它参考1


如果有人想要更高级的东西,请尝试RequireJS。您将获得额外的好处,例如依赖关系管理,更好的并发性,并避免重复(即,多次检索脚本)。[129]


您可以在模块中编写JavaScript文件,然后在其他脚本中将它们作为依赖项引用。或者您可以将RequireJS用作简单的go get this script解决方案。


例:


将依赖项定义为模块:


一些-dependency.js


define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {

     //Your actual script goes here.   
     //The dependent scripts will be fetched if necessary.

     return libraryObject;  //For example, jQuery object
});


implementation.js 是依赖于 some-dependency.js 的主要JavaScript文件


require(['some-dependency'], function(dependency) {

    //Your script goes here
    //some-dependency.js is fetched.   
    //Then your script is executed
});


摘自GitHub自述文件:[130]



  RequireJS加载纯JavaScript文件以及更多定义
  模块。它针对浏览器内使用进行了优化,包括在Web中
  工作者,但它可以在其他JavaScript环境中使用,例如
  犀牛和节点。它实现了异步模块API。

  
  RequireJS使用普通脚本标签来加载模块/文件,因此它应该
  允许轻松调试。它可以简单地用于加载现有的
  JavaScript文件,因此您可以将其添加到现有项目中
  必须重新编写JavaScript文件。


  
  ...


其它参考2


实际上是一种异步加载JavaScript文件而不是的方法,因此您可以在加载后立即使用新加载文件中包含的函数,我认为它可以在所有浏览器。


您需要在页面的<head>元素上使用jQuery.append(),即:


$("head").append('<script type="text/javascript" src="' + script + '"></script>');


但是,此方法也存在一个问题:如果导入的JavaScript文件中发生错误,Firebug(以及Firefox错误控制台和Chrome开发人员工具)也会错误地报告其位置,如果您使用Firebug跟踪这是一个大问题JavaScript错误很多(我这样做)。由于某种原因,Firebug根本不知道新加载的文件,因此如果该文件中发生错误,它会报告它发生在您的主HTML文件中,并且您将无法找到错误的真正原因。[[[131] [132] [133]


但如果这对您来说不是问题,那么这种方法应该可行。


我实际上编写了一个名为 $ .import_js()的jQuery插件,该插件使用以下方法:


(function($)
{
    /*
     * $.import_js() helper (for JavaScript importing within JavaScript code).
     */
    var import_js_imported = [];

    $.extend(true,
    {
        import_js : function(script)
        {
            var found = false;
            for (var i = 0; i < import_js_imported.length; i++)
                if (import_js_imported[i] == script) {
                    found = true;
                    break;
                }

            if (found == false) {
                $("head").append('<script type="text/javascript" src="' + script + '"></script>');
                import_js_imported.push(script);
            }
        }
    });

})(jQuery);


所以你需要做的就是导入JavaScript:


$.import_js('/path_to_project/scripts/somefunctions.js');


我也在例子中做了一个简单的测试。[134]


它包含主HTML中的main.js文件,然后main.js中的脚本使用$.import_js()导入名为included.js的附加文件,该文件定义了此函数:


function hello()
{
    alert("Hello world!");
}


在包含included.js之后,调用hello()函数,您就会得到警报。


(这个答案是对e-satisf评论的回应)。

其它参考3


另一种方式,在我看来更清晰,是制作同步Ajax请求而不是使用<script>标记。这也是Node.js处理的方式。[135]


这是使用jQuery的一个例子:


function require(script) {
    $.ajax({
        url: script,
        dataType: "script",
        async: false,           // <-- This is the key
        success: function () {
            // all good...
        },
        error: function () {
            throw new Error("Could not load script " + script);
        }
    });
}


然后,您可以在代码中使用它,因为您通常使用包含:


require("/scripts/subscript.js");


并且能够在下一行中从所需脚本调用函数:


subscript.doSomethingCool(); 

其它参考4


有一个好消息要告诉你。很快您就可以轻松加载JavaScript代码了。它将成为导入JavaScript代码模块的标准方式,并将成为核心JavaScript本身的一部分。


您只需编写import cond from 'cond.js';从文件cond.js加载名为cond的宏。


因此,您不必依赖任何JavaScript框架,也不必显式地进行Ajax调用。[136]


参考:



  • 静态模块分辨率 [137]

  • 模块加载器 [138]


其它参考5


可以动态生成JavaScript标记,并将其从其他JavaScript代码中添加到HTML文档中。这将加载有针对性的JavaScript文件。


function includeJs(jsFilePath) {
    var js = document.createElement("script");

    js.type = "text/javascript";
    js.src = jsFilePath;

    document.body.appendChild(js);
}

includeJs("/path/to/some/file.js");

其它参考6


声明import在ECMAScript 6中。[139]


句法


import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name" as name;

其它参考7


也许您可以使用我在此页面上找到的此功能如何在JavaScript文件中包含JavaScript文件?:[140]


function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';

    head.appendChild(script)
}

其它参考8


这是一个同步版本没有jQuery :


function myRequire( url ) {
    var ajax = new XMLHttpRequest();
    ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous
    ajax.onreadystatechange = function () {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4) {
            switch( ajax.status) {
                case 200:
                    eval.apply( window, [script] );
                    console.log("script loaded: ", url);
                    break;
                default:
                    console.log("ERROR: script not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}


请注意,要使此跨域工作,服务器需要在其响应中设置allow-origin标头。

其它参考9


我刚写了这个JavaScript代码(使用Prototype进行DOM操作):[141] [142]


var require = (function() {
    var _required = {};
    return (function(url, callback) {
        if (typeof url == 'object') {
            // We've (hopefully) got an array: time to chain!
            if (url.length > 1) {
                // Load the nth file as soon as everything up to the
                // n-1th one is done.
                require(url.slice(0, url.length - 1), function() {
                    require(url[url.length - 1], callback);
                });
            } else if (url.length == 1) {
                require(url[0], callback);
            }
            return;
        }
        if (typeof _required[url] == 'undefined') {
            // Haven't loaded this URL yet; gogogo!
            _required[url] = [];

            var script = new Element('script', {
                src: url,
                type: 'text/javascript'
            });
            script.observe('load', function() {
                console.log("script " + url + " loaded.");
                _required[url].each(function(cb) {
                    cb.call(); // TODO: does this execute in the right context?
                });
                _required[url] = true;
            });

            $$('head')[0].insert(script);
        } else if (typeof _required[url] == 'boolean') {
            // We already loaded the thing, so go ahead.
            if (callback) {
                callback.call();
            }
            return;
        }

        if (callback) {
            _required[url].push(callback);
        }
    });
})();


用法:


<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
    require(['foo.js','bar.js'], function () {
        /* Use foo.js and bar.js here */
    });
</script>


要点:http://gist.github.com/284442。[143]

其它参考10


这是Facebook为无处不在的Like按钮做广告的一般化版本:




<script>
  var firstScript = document.getElementsByTagName('script')[0],
      js = document.createElement('script');
  js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
  js.onload = function () {
    // do stuff with your dynamically loaded script
    snowStorm.snowColor = '#99ccff';
  };
  firstScript.parentNode.insertBefore(js, firstScript);
</script>



在我看来,这可能是JavaScript的最大弱点。多年来,依赖关系跟踪让我无法解决问题。无论如何,似乎唯一的实用解决方案是在HTML文件中使用脚本包含因此可怕地使您的JavaScript代码依赖在用户包括您需要的来源并使重用不友好。


对不起,如果这是一个讲座;)这是我的一个(坏)习惯,但我想说明这一点。


这个问题与网络上的所有其他问题一样,即JavaScript的历史。它实际上并没有被设计成以今天使用的广泛方式使用。 Netscape制作了一种语言,可以让你控制一些东西,但他们并没有设想它被广泛用于现在这么多的东西,并且出于某种原因它从那里扩展而没有解决一些问题。原策略的根本弱点。[144]


当然并不孤单.HTML并不是为现代网页设计的;它被设计成一种表达文档逻辑的方式,以便读者(现代世界中的浏览器)能够以系统能力范围内的适用形式显示它,并且需要数年时间才能找到解决方案(其他而不是MS和Netscape的黑客入侵。 CSS解决了这个问题,但是要花费很长时间才能让人们使用它而不是使用既定的BAD技术。它发生了,赞美。[145]


希望JavaScript(特别是现在它是标准的一部分)将发展为接受适当的模块化(以及其他一些东西)的概念,就像世界上其他(现存的)编程语言一样,这种愚蠢将会消失在那之前你只是不喜欢它并把它弄糟,我害怕。

其它参考11


如果你想要纯JavaScript,你可以使用document.write


document.write('<script src="myscript.js" type="text/javascript"></script>');


如果使用jQuery库,则可以使用$.getScript方法。


$.getScript("another_script.js");

其它参考12


这里显示的大多数解决方案都意味着动态加载。我正在搜索一个编译器,它将所有依赖的文件组合成一个输出文件。与Less/Sass预处理器相同,处理CSS @import at-rule。由于我没有找到这种类似的东西,我写了一个解决问题的简单工具。[146] [147]


所以这里是编译器https://github.com/dsheiko/jsic,它可以安全地用$import("file-path")替换所请求的文件内容。这是相应的Grunt插件:https://github.com/dsheiko/grunt-jsic。[148] [149]:[150]


在jQuery master分支上,他们只是将原子源文件连接成一个以intro.js开头并以outtro.js结尾的文件。这不适合我,因为它没有提供源代码设计的灵活性。看看它如何与jsic一起工作:


的src/main.js


var foo = $import("./Form/Input/Tel");


SRC/形式/输入/Tel.js


function() {
    return {
          prop: "",
          method: function(){}
    }
}


现在我们可以运行编译器了:


node jsic.js src/main.js build/mail.js


并获得组合文件


建立/main.js


var foo = function() {
    return {
          prop: "",
          method: function(){}
    }
};

其它参考13


您还可以使用PHP组装脚本:[151]


档案main.js.php:


<?php
    header('Content-type:text/javascript; charset=utf-8');
    include_once("foo.js.php");
    include_once("bar.js.php");
?>

// Main JavaScript code goes here

其它参考14


这应该做:


xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);

其它参考15


如果您打算使用导入/包含文件中的函数加载JavaScript文件,则还可以定义全局对象并将函数设置为对象项。例如:


global.js



A = {};


file1.js



A.func1 = function() {
  console.log("func1");
}


file2.js



A.func2 = function() {
  console.log("func2");
}


main.js



A.func1();
A.func2();


在HTML文件中包含脚本时,您需要小心。订单应如下所示:


<head>
  <script type="text/javascript" src="global.js"></script>
  <script type="text/javascript" src="file1.js"></script>
  <script type="text/javascript" src="file2.js"></script>
  <script type="text/javascript" src="main.js"></script>
</head>

其它参考16


或者不是在运行时包括在上载之前使用脚本连接。


我使用Sprockets(我不知道是否还有其他人)。您在单独的文件中构建JavaScript代码,并包含由Sprockets引擎作为包括处理的注释。对于开发,您可以按顺序包含文件,然后生产以合并它们... [152]


也可以看看:



  • 介绍Sprockets:JavaScript依赖关系管理和连接


其它参考17


如果您正在使用Web Workers并希望在worker的范围内包含其他脚本,则提供的有关向head标签等添加脚本的其他答案将不适用于您。[153] [[[154]


幸运的是,Web Workers有自己的importScripts函数,它是Web Worker范围内的全局函数,它本身就是浏览器本身,因为它是规范的一部分。[155] [156]


或者,作为对您的问题的第二高投票答案,RequireJS还可以处理Web Worker中的脚本(可能调用importScripts本身,但还有一些其他有用的功能)。 [158]]]

其它参考18


我有一个简单的问题,但我对这个问题的回答感到困惑。


我不得不在另一个JavaScript文件(main.js)中使用一个JavaScript文件(myvariables.js)中定义的变量(myVar1)。


为此,我做了如下:


以正确的顺序加载HTML文件中的JavaScript代码,首先是myvariables.js,然后是main.js:


<html>
    <body onload="bodyReady();" >

        <script src="myvariables.js" > </script>
        <script src="main.js" > </script>

        <!-- Some other code -->
    </body>
</html>


文件:myvariables.js


var myVar1 = "I am variable from myvariables.js";


文件:main.js


// ...
function bodyReady() {
    // ...
    alert (myVar1);    // This shows "I am variable from myvariables.js", which I needed
    // ...
}
// ...


如您所见,我在另一个JavaScript文件中的一个JavaScript文件中使用了一个变量,但我不需要在另一个JavaScript文件中包含一个。我只需要确保在第二个JavaScript文件之前加载第一个JavaScript文件,并且第一个JavaScript文件的变量可以在第二个JavaScript文件中自动访问。


这节省了我的一天。我希望这有帮助。

其它参考19


使用诸如Mixture之类的工具通过其特殊的.mix文件类型(参见此处)可以实现用于实现类似CSS的JavaScript导入的@import语法。我想应用程序只是在内部使用上述方法之一,但我不知道。[159]


.mix文件的混合文档中:



  混合文件只是带有.mix的.js或.css文件。在文件名中。一个
  mix文件只是扩展了普通样式的功能
  脚本文件,允许您导入和组合。



这是一个将多个.js文件合并为一个的.mix文件示例:


// scripts-global.mix.js
// Plugins - Global

@import "global-plugins/headroom.js";
@import "global-plugins/retina-1.1.0.js";
@import "global-plugins/isotope.js";
@import "global-plugins/jquery.fitvids.js";


混合物将其输出为scripts-global.js,也作为缩小版本(scripts-global.min.js)。


注意:除了使用它作为前端开发工具之外,我与Mixture没有任何关联。我在看到.mix JavaScript文件的实际应用时遇到了这个问题(在其中一个Mixture样板中)并且对它感到有点困惑(你能做到这一点吗?我想到了自己。)然后我意识到这是一个特定于应用程序的文件类型(有点令人失望,同意)。然而,认为这些知识可能对其他人有帮助。


更新:混合现在是免费的(离线)。[160]


更新:混合物现已停止使用。旧的混合物释放仍然可用[161]

其它参考20


我编写了一个简单的模块,可以自动执行在JavaScript中导入/包含模块脚本的工作。有关代码的详细说明,请参阅博客文章 JavaScript require/import/include modules 。[162]


// ----- USAGE -----

require('ivar.util.string');
require('ivar.net.*');
require('ivar/util/array.js');
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js');

ready(function(){
    //Do something when required scripts are loaded
});

    //--------------------

var _rmod = _rmod || {}; //Require module namespace
_rmod.LOADED = false;
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
    scripts: {},
    length: 0
};

_rmod.findScriptPath = function(script_name) {
    var script_elems = document.getElementsByTagName('script');
    for (var i = 0; i < script_elems.length; i++) {
        if (script_elems[i].src.endsWith(script_name)) {
            var href = window.location.href;
            href = href.substring(0, href.lastIndexOf('/'));
            var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
            return url.substring(href.length+1, url.length);
        }
    }
    return '';
};

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark
                                                   //the root directory of your library, any library.


_rmod.injectScript = function(script_name, uri, callback, prepare) {

    if(!prepare)
        prepare(script_name, uri);

    var script_elem = document.createElement('script');
    script_elem.type = 'text/javascript';
    script_elem.title = script_name;
    script_elem.src = uri;
    script_elem.async = true;
    script_elem.defer = false;

    if(!callback)
        script_elem.onload = function() {
            callback(script_name, uri);
        };
    document.getElementsByTagName('head')[0].appendChild(script_elem);
};

_rmod.requirePrepare = function(script_name, uri) {
    _rmod.loading.scripts[script_name] = uri;
    _rmod.loading.length++;
};

_rmod.requireCallback = function(script_name, uri) {
    _rmod.loading.length--;
    delete _rmod.loading.scripts[script_name];
    _rmod.imported[script_name] = uri;

    if(_rmod.loading.length == 0)
        _rmod.onReady();
};

_rmod.onReady = function() {
    if (!_rmod.LOADED) {
        for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
            _rmod.on_ready_fn_stack[i]();
        });
        _rmod.LOADED = true;
    }
};

_.rmod = namespaceToUri = function(script_name, url) {
    var np = script_name.split('.');
    if (np.getLast() === '*') {
        np.pop();
        np.push('_all');
    }

    if(!url)
        url = '';

    script_name = np.join('.');
    return  url + np.join('/')+'.js';
};

//You can rename based on your liking. I chose require, but it
//can be called include or anything else that is easy for you
//to remember or write, except "import", because it is reserved
//for future use.
var require = function(script_name) {
    var uri = '';
    if (script_name.indexOf('/') > -1) {
        uri = script_name;
        var lastSlash = uri.lastIndexOf('/');
        script_name = uri.substring(lastSlash+1, uri.length);
    } 
    else {
        uri = _rmod.namespaceToUri(script_name, ivar._private.libpath);
    }

    if (!_rmod.loading.scripts.hasOwnProperty(script_name)
     && !_rmod.imported.hasOwnProperty(script_name)) {
        _rmod.injectScript(script_name, uri,
            _rmod.requireCallback,
                _rmod.requirePrepare);
    }
};

var ready = function(fn) {
    _rmod.on_ready_fn_stack.push(fn);
};

其它参考21


我通常的方法是:


var require = function (src, cb) {
    cb = cb || function () {};

    var newScriptTag = document.createElement('script'),
        firstScriptTag = document.getElementsByTagName('script')[0];
    newScriptTag.src = src;
    newScriptTag.async = true;
    newScriptTag.onload = newScriptTag.onreadystatechange = function () {
        (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());
    };
    firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);
}


它工作得很好,并没有为我使用页面重新加载。我已经尝试过AJAX方法(其中一个答案),但它似乎对我来说并不好用。


这里解释了代码如何为那些好奇的人工作:实际上,它创建了一个新的脚本标记(在第一个之后)。它将它设置为异步模式,因此它不会阻止其余的代码,但当readyState(要加载的内容的状态)更改为已加载时调用回调。

其它参考22


var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

其它参考23


此脚本将JavaScript文件添加到任何其他<script>标记的顶部:


(function () {
    var li = document.createElement('script'); 
    li.type = 'text/javascript'; 
    li.src= "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; 
    li.async=true; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(li, s);
})();

其它参考24


还有Head.js.这很容易处理:[163]


head.load("js/jquery.min.js",
          "js/jquery.someplugin.js",
          "js/jquery.someplugin.css", function() {
  alert("Everything is ok!");
});


如你所见,它比Require.js更容易,并且像jQuery的$.getScript方法一样方便。它还具有一些高级功能,如条件加载,特征检测等等。[164]

其它参考25


用现代语言来说就是这样


function loadJs( url ){
  return new Promise( resolve => {
    const script = document.createElement( "script" );
    script.src = url;
    script.onload = resolve;
    document.head.appendChild( script );
  });
}

其它参考26


我来到这个问题是因为我正在寻找一种简单的方法来维护一组有用的JavaScript插件。在看到这里的一些解决方案之后,我想出了这个:



  1. 设置一个名为plugins.js(或extensions.js或者你有什么)的文件。将插件文件与一个主文件保持在一起。

  2. plugins.js将有一个名为pluginNames [[]]的数组,我们将遍历每个(),
    然后为每个插件在头部附加一个标签


    //在我们添加或删除插件文件时设置要更新的数组
     var pluginNames=[[刻字,fittext,butterjam等]];
    //每个插件的一个脚本标记
     $ .each(pluginNames,function(){
       $( 头)追加( )。
     });

  3. 手动调用你头脑中的一个文件:

    <script src="js/plugins/plugins.js"></script>



我发现即使所有的插件都按照他们应该的方式放入头标签,但当你点击页面或刷新时,他们并不总是被浏览器运行。


我发现在PHP包中编写脚本标记更加可靠。你只需要编写一次,这与使用JavaScript调用插件一样多。

其它参考27


这个问题有很多可能的答案。我的回答显然基于其中的一些。这是我在阅读完所有答案后最终得到的结论。


$.getScript以及加载完成时需要回调的任何其他解决方案的问题是,如果您有多个文件使用它并相互依赖,则您无法知道何时加载了所有脚本(一旦它们嵌套在多个文件中)。


实施例



file3.js


var f3obj = "file3";

// Define other stuff


file2.js:


var f2obj = "file2";
$.getScript("file3.js", function(){

    alert(f3obj);

    // Use anything defined in file3.
});


file1.js:


$.getScript("file2.js", function(){
    alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
    alert(f2obj);

    // Use anything defined in the loaded script...
});


当你说你可以指定Ajax同步运行或使用XMLHttpRequest时你是对的,但当前的趋势似乎是弃用同步请求,所以你现在或将来可能无法获得完整的浏览器支持。[165]


您可以尝试使用$.when来检查延迟对象的数组,但现在您在每个文件中执行此操作,并且只要执行$.when而不执行回调,file2将被视为已加载,因此file1在加载file3之前仍然继续执行。这仍然有同样的问题。


我决定倒退而不是前锋。谢谢document.writeln。我知道它是禁忌,但只要它被正确使用就行得很好。你最终得到的代码可以很容易地调试,在DOM中正确显示并且可以确保正确加载依赖关系的顺序。


你当然可以使用$(body)。append(),但是你再也无法正确调试了。


注意:您必须仅在页面加载时使用此选项,否则您将获得一个空白屏幕。换句话说,始终将此放在document.ready 之前/之外。在点击事件或类似事件中加载页面后,我没有使用过此测试,但我很确定它会失败。


我喜欢扩展jQuery的想法,但显然你不需要。


在打电话之前document.writeln,它通过评估所有脚本元素来检查以确保脚本尚未加载。


我假设在执行document.ready事件之前脚本没有完全执行。 (我知道使用document.ready不是必需的,但很多人使用它,处理这个是一种保障。)


加载其他文件时,document.ready回调将以错误的顺序执行。为了在实际加载脚本时解决此问题,导入它的脚本将自行重新导入并暂停执行。这会导致原始文件现在在其导入的任何脚本之后执行其document.ready回调。


您可以尝试修改jQuery readyList而不是这种方法,但这似乎是一个更糟糕的解决方案。


解:


$.extend(true,
{
    import_js : function(scriptpath, reAddLast)
    {
        if (typeof reAddLast === "undefined" || reAddLast === null)
        {
            reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
        }

        var found = false;
        if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
        {
            found = $('script').filter(function () {
                return ($(this).attr('src') == scriptpath);
            }).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
        }

        if (found == false) {

            var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.

            document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln

            if (reAddLast)
            {
                $.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
                throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
            }
            return true;
        }
        return false;
    }
});


用法:


文件3:


var f3obj = "file3";

// Define other stuff
$(function(){
    f3obj = "file3docready";
});


文件2:


$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
    f2obj = "file2docready";
});


文件1:


$.import_js('js/file2.js');

// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"

$(function(){
    // Use objects from file2 or file3 some more.
    alert(f3obj); //"file3docready"
    alert(f2obj); //"file2docready"
});

其它参考28


我创建了一个函数,允许您使用与C#/Java类似的措辞来包含JavaScript文件。我甚至从另一个 JavaScript文件内部进行了一些测试,它似乎也可以工作。它确实需要jQuery,最后需要一些魔术。


我把这段代码放在脚本目录根目录下的文件中(我把它命名为global.js,但是你可以使用你想要的任何东西。除非我错了,jQuery应该是给定页面上唯一需要的脚本请注意,除了一些基本用法之外,这在很大程度上是未经测试的,因此我可能会或可能不会有任何问题;使用自己的风险yadda yadda如果你把yadda yadda搞砸了,我不负责任:


/**
* @fileoverview This file stores global functions that are required by other libraries.
*/

if (typeof(jQuery) === 'undefined') {
    throw 'jQuery is required.';
}

/** Defines the base script directory that all .js files are assumed to be organized under. */
var BASE_DIR = 'js/';

/**
* Loads the specified file, outputting it to the <head> HTMLElement.
*
* This method mimics the use of using in C# or import in Java, allowing
* JavaScript files to "load" other JavaScript files that they depend on
* using a familiar syntax.
*
* This method assumes all scripts are under a directory at the root and will
* append the .js file extension automatically.
*
* @param {string} file A file path to load using C#/Java "dot" syntax.
*
* Example Usage:
* imports('core.utils.extensions');
* This will output: <script type="text/javascript" src="/js/core/utils/extensions.js"></script>
*/
function imports(file) {
    var fileName = file.substr(file.lastIndexOf('.') + 1, file.length);

    // Convert PascalCase name to underscore_separated_name
    var regex = new RegExp(/([A-Z])/g);
    if (regex.test(fileName)) {
        var separated = fileName.replace(regex, ",$1").replace(',', '');
        fileName = separated.replace(/[,]/g, '_');
    }

    // Remove the original JavaScript file name to replace with underscore version
    file = file.substr(0, file.lastIndexOf('.'));

    // Convert the dot syntax to directory syntax to actually load the file
    if (file.indexOf('.') > 0) {
        file = file.replace(/[.]/g, '/');
    }

    var src = BASE_DIR + file + '/' + fileName.toLowerCase() + '.js';
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;

    $('head').find('script:last').append(script);
}