繁体   English   中英

如何在另一个 JavaScript 文件中包含一个 JavaScript 文件?

[英]How do I include a JavaScript file in another JavaScript file?

如何在另一个 JavaScript 文件中包含一个 JavaScript 文件,类似于 CSS 中的@import

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

但自 2015 年(ES6)以来,JavaScript 已经有了ES6 模块标准来在 Node.js 中导入模块,大多数现代浏览器也支持这一点。

为了与旧浏览器兼容,可以使用WebpackRollup等构建工具和/或Babel等转译工具。

ES6 模块

从 v8.5 开始, Node.js 支持ECMAScript (ES6) 模块,带有--experimental-modules标志,至少从没有标志的 Node.js v13.8.0 开始。 要启用“ESM”(与 Node.js 以前的 CommonJS 样式模块系统 [“CJS”] 相比),您可以在package.json中使用"type": "module" ,或者为文件提供扩展名.mjs (类似地,如果您的默认值为 ESM,则使用 Node.js 以前的 CJS 模块编写的模块可以命名为.cjs 。)

使用package.json

{
    "type": "module"
}

然后module.js

export function hello() {
  return "Hello";
}

然后main.js

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

使用.mjs ,您将拥有module.mjs

export function hello() {
  return "Hello";
}

然后main.mjs

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

浏览器中的 ECMAScript 模块

Safari 10.1、Chrome 61、Firefox 60 和 Edge 16 以来,浏览器已经支持直接加载 ECMAScript 模块(不需要像 Webpack 这样的工具)。在caniuse上查看当前支持。 无需使用 Node.js 的.mjs扩展名; 浏览器完全忽略模块/脚本上的文件扩展名。

<script type="module">
  import { hello } from './hello.mjs'; // Or the extension could be just `.js`
  hello('world');
</script>
// hello.mjs -- or the extension could be just `.js`
export function hello(text) {
  const div = document.createElement('div');
  div.textContent = `Hello ${text}`;
  document.body.appendChild(div);
}

阅读更多https://jakearchibald.com/2017/es-modules-in-browsers/

浏览器中的动态导入

动态导入让脚本根据需要加载其他脚本:

<script type="module">
  import('hello.mjs').then(module => {
      module.hello('world');
    });
</script>

https://developers.google.com/web/updates/2017/11/dynamic-import阅读更多内容

Node.js 需要

在 Node.js 中仍然广泛使用的旧 CJS 模块样式是module.exports / require系统。

// 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也为错误、黑客和安全问题打开了大门。

获取加载

与动态导入一样,您可以使用fetch调用加载一个或多个脚本,使用 Promise 来使用Fetch Inject库控制脚本依赖项的执行顺序:

fetchInject([
  'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
  console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})

jQuery 加载

jQuery在一行中提供了加载功能:

$.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");  // create a script DOM node
    script.src = url;  // set its 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>标记,其中src属性设置为作为第一个参数提供给函数的 URL。

这两种解决方案都在JavaScript Madness: Dynamic Sc​​ript Loading中进行了讨论和说明。

检测脚本何时执行

现在,有一个大问题你必须知道。 这样做意味着您远程加载代码 现代网络浏览器将加载文件并继续执行您当前的脚本,因为它们异步加载所有内容以提高性能。 (这适用于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.head;
    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 函数中加载脚本后编写要使用的代码:

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

然后你运行所有这些:

loadScript("my_lovely_script.js", myPrettyCode);

请注意,脚本可能在 DOM 加载之后或之前执行,具体取决于浏览器以及您是否包含行script.async = false; . 有一篇很棒的关于 Javascript 加载的文章讨论了这个问题。

源代码合并/预处理

如本答案顶部所述,许多开发人员在他们的项目中使用 Parcel、Webpack 或 Babel 等构建/转换工具,允许他们使用即将推出的 JavaScript 语法,为旧浏览器提供向后兼容性,合并文件,缩小,执行代码拆分等

如果有人在寻找更高级的东西,试试RequireJS 您将获得额外的好处,例如依赖关系管理、更好的并发性和避免重复(即多次检索脚本)。

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

例子:

将依赖项定义为模块:

一些依赖.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是你的“主要”JavaScript 文件,它依赖于some-dependency.js

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

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

摘自GitHub自述文件:

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

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

...

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

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

$("head").append($("<script></script>").attr("src", url));

/* Note that following line of code is incorrect because it doesn't escape the
 * HTML attribute src correctly and will fail if `url` contains special characters:
 * $("head").append('<script src="' + url + '"></script>');
 */

但是,这种方法也有一个问题:如果导入的 JavaScript 文件发生错误, Firebug (还有 Firefox 错误控制台和Chrome 开发者工具)会错误地报告它的位置,如果使用 Firebug 跟踪,这是一个大问题JavaScript 错误很多(我愿意)。 Firebug 出于某种原因根本不知道新加载的文件,因此如果该文件中发生错误,它会报告它发生在您的主HTML文件中,您将很难找出错误的真正原因。

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

我实际上编写了一个名为$.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></script').attr('src', script));
                import_js_imported.push(script);
            }
        }
    });
    
})(jQuery);

因此,导入 JavaScript 所需要做的就是:

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

我还在Example对此做了一个简单的测试。

它在主 HTML 中包含一个main.js文件,然后 main.js 中的脚本使用$.import_js() main.js一个名为 include.js 的included.js文件,该文件定义了这个函数:

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

included.js include.js 之后,立即调用hello()函数,您会收到警报。

(此答案是对 e-satis 评论的回应)。

另一种在我看来更简洁的方法是发出同步 Ajax 请求,而不是使用<script>标记。 这也是Node.js处理包括的方式。

这是一个使用 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(); 

可以动态生成 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");

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

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

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

参考:

语句import在 ECMAScript 6 中。

句法

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;

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

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

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

    head.appendChild(script)
}

这是一个没有 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标头。

我刚刚编写了这段 JavaScript 代码(使用Prototype进行DOM操作):

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

如果你想在纯 JavaScript 中使用它,你可以使用document.write

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

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

$.getScript("another_script.js");

以下是 Facebook 如何为其无处不在的“点赞”按钮所做的通用版本:

 <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>

如果它适用于 Facebook,它将适用于您。

我们寻找第一个script元素而不是headbody的原因是因为某些浏览器在丢失时不会创建一个,但我们保证有一个script元素 - 这个。 http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/阅读更多内容。

您还可以使用PHP组装您的脚本:

文件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

此处显示的大多数解决方案都意味着动态加载。 我正在寻找一个编译器,它将所有依赖的文件组装成一个输出文件。 Less / Sass预处理器处理 CSS @import at-rule 相同。 由于我没有找到任何像样的东西,我写了一个简单的工具来解决这个问题。

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

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

src/main.js

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

src/Form/Input/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(){}
    }
};

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

global.js

A = {};

文件1.js

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

文件2.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>

这应该这样做:

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

或者,不是在运行时包含,而是在上传之前使用脚本进行连接。

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

也可以看看:

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

我必须在另一个 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 文件中自动访问。

这拯救了我的一天。 我希望这有帮助。

用于实现类似 CSS 的 JavaScript 导入的@import语法可以使用诸如 Mixture 之类的工具通过其特殊的.mix文件类型(参见此处)来实现。 我假设应用程序通过上述方法之一执行此操作。

.mix文件的 Mixture 文档中:

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

这是一个将多个.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";

Mixture 将其输出为scripts-global.js以及缩小版本( scripts-global.min.js )。

注意:除了将它用作前端开发工具外,我与 Mixture 没有任何关系。 我在看到一个正在运行的.mix JavaScript 文件(在其中一个 Mixture 样板中)并对此感到有些困惑时遇到了这个问题(“你可以这样做吗?”我心想)。 然后我意识到这是一个特定于应用程序的文件类型(有点令人失望,同意)。 尽管如此,认为这些知识可能对其他人有所帮助。

注意: Mixture 于 2016/07/26 停产(在 2015/04/12 开源之后)。

在检查脚本是否已经加载的现代语言中,它将是:

function loadJs( url ){
  return new Promise(( resolve, reject ) => {
    if (document.querySelector( `head > script[ src = "${url}" ]`) !== null ){
        console.warn( `script already loaded: ${url}` );
        resolve();
    }
    const script = document.createElement( "script" );
    script.src = url;
    script.onload = resolve;
    script.onerror = function( reason ){
        // This can be useful for your error-handling code
        reason.message = `error trying to load script ${url}`;
        reject( reason );
    };
    document.head.appendChild( script );
  });
}

用法(异步/等待):

try { await loadJs("https://.../script.js"); }
catch(error) { console.log(error); }

或者

await loadJs( "https://.../script.js" ).catch( err => {} );

用法(承诺):

loadJs( "https://.../script.js" ).then( res => {} ).catch( err => {} );

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

幸运的是, Web Worker 有自己的importScripts函数,它是 Web Worker 范围内的全局函数,是浏览器本身的原生函数,因为它是规范的一部分

或者,作为对您的问题的第二高投票答案突出显示RequireJS还可以处理在 Web Worker 中包含脚本(可能会调用importScripts本身,但具有一些其他有用的功能)。

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

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

document.body.appendChild(js);

尽管这些答案很棒,但自从脚本加载存在以来就有一个简单的“解决方案”,它将涵盖大多数人的 99.999% 的用例。 只需在需要它的脚本之前包含您需要的脚本。 对于大多数项目来说,确定需要哪些脚本以及按什么顺序并不需要很长时间。

<!DOCTYPE HTML>
<html>
    <head>
        <script src="script1.js"></script>
        <script src="script2.js"></script>
    </head>
    <body></body>
</html>

如果 script2 需要 script1,这确实是执行此类操作的最简单方法。 我很惊讶没有人提出这个问题,因为这是最明显和最简单的答案,几乎适用于每一个案例。

ES6 模块

的,在脚本标签(支持)中使用 type="module":

<script type="module" src="script.js"></script>

script.js文件中包含另一个文件,如下所示:

import { hello } from './module.js';
...
// alert(hello());

在“module.js”中,您必须导出要导入的函数/类

export function hello() {
    return "Hello World";
}

一个工作示例是here

我常用的方法是:

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 方法(其他答案之一),但它似乎对我来说效果不佳。

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

我编写了一个简单的模块,它可以自动执行在 JavaScript 中导入/包含模块脚本的工作。 代码的详细解释可以参考博文JavaScript require / import / include modules

// ----- 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);
};

此脚本会将 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);
})();

让它保持美观、简短、简单和可维护! :]

// Third-party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

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

// Initialize a single load
load('plugins/script.js');

// Initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

此代码只是一个简短的功能示例,可能需要额外的特性功能才能在任何(或给定)平台上完全支持。

有几种方法可以在 JavaScript 中实现模块。 以下是两个最受欢迎的:

ES6 模块

浏览器还不支持这种模块化系统,所以为了让你使用这种语法,你必须使用像Webpack这样的捆绑器。 无论如何,使用捆绑器会更好,因为这可以将所有不同的文件组合成一个(或几个相关的)文件。 这将更快地从服务器向客户端提供文件,因为每个 HTTP 请求都伴随着一些相关的开销。 因此,通过减少整体 HTTP 请求,我们提高了性能。 下面是一个 ES6 模块的例子:

// main.js file

export function add (a, b) {
  return a + b;
}

export default function multiply (a, b) {
  return a * b;
}


// test.js file

import {add}, multiply from './main';   // For named exports between curly braces {export1, export2}
                                        // For default exports without {}

console.log(multiply(2, 2));  // logs 4

console.log(add(1, 2));  // logs 3

CommonJS (在 Node.js 中使用)

这个模块化系统用于 Node.js。 您基本上将您的导出添加到一个名为module.exports的对象中。 然后,您可以通过require('modulePath')访问此对象。 这里重要的是要意识到这些模块正在被缓存,所以如果你require()某个模块两次,它将返回已经创建的模块。

// main.js file

function add (a, b) {
  return a + b;
}

module.exports = add;  // Here we add our 'add' function to the exports object


// test.js file

const add = require('./main');

console.log(add(1,2));  // logs 3

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

  1. 设置一个名为“plugins.js”(或 extensions.js 或任何你想要的)的文件。 将您的插件文件与那个主文件保存在一起。

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

//set array to be updated when we add or remove plugin files
var pluginNames = ["lettering", "fittext", "butterjam", etc.];

//one script tag for each plugin
$.each(pluginNames, function(){
    $('head').append('<script src="js/plugins/' + this + '.js"></script>');
});
  1. 手动调用你脑海中的一个文件:
    <script src="js/plugins/plugins.js"></script>

但:

即使所有插件都以应有的方式放入 head 标签中,但当您单击页面或刷新时,它们并不总是由浏览器运行。

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

是的,有...

继续阅读。 ES6中,我们可以将部分或整个 JavaScript 文件exportimport到另一个文件中......

但是等等,并不是所有的浏览器都支持ES6 ,所以你需要使用babel.js来转译它……

因此,您创建了一个如下所示的类:

class Person {
  constructor(name) {
    this.name = name;
  }

  build() {
    return new Person(this);
  }
}

module.exports = Person;

另一个JavaScript 文件中,执行如下导入:

import { Person } from 'Person';

您还可以要求该文件,例如:

const Person = require('./Person');

如果您使用的是较旧的 JavaScript 版本,则可以使用requirejs

requirejs(["helper/util"], function(util) {
    // This function is called when scripts/helper/util.js is loaded.
    // If util.js calls define(), then this function is not fired until
    // util's dependencies have loaded, and the util argument will hold
    // the module value for "helper/util".
});

如果你想坚持使用旧版本的东西,比如jQuery ,你也可以使用getScript 之类的东西:

jQuery.getScript('./another-script.js', function() {
    // Call back after another-script loaded
});

最后但并非最不重要的一点是,不要忘记您可以使用<script>标记将脚本放在一起的传统方式...

<script src="./first-script.js"></script>
<script src="./second-script.js"></script>
<script src="./third-script.js"></script>

还有我应该在这里提到的asyncdefer属性......

注意:有几种方法可以执行外部脚本:

  • 如果存在异步:脚本与页面的其余部分异步执行(脚本将在页面继续解析时执行)
  • 如果 async 不存在并且 defer 存在:当页面完成解析时执行脚本
  • 如果 async 或 defer 都不存在:在浏览器继续解析页面之前立即获取并执行脚本

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

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

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

这个问题有很多潜在的答案。 我的回答显然是基于其中的一些。 这是我在阅读所有答案后得出的结论。

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

例子:

文件 3.js

var f3obj = "file3";

// Define other stuff

文件2.js:

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

    alert(f3obj);

    // Use anything defined in file3.
});

文件 1.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时,您是对的,但目前的趋势似乎是弃用同步请求,因此您现在或将来可能无法获得完整的浏览器支持。

您可以尝试使用$.when来检查延迟对象的数组,但是现在您在每个文件中都这样做,并且 file2 将在$.when被执行时被认为是加载,而不是在回调执行时被加载,所以 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"
});

这是使用 HTML 导入的浏览器(不是 Node.js)的解决方法。

首先,所有 JavaScript 类和脚本都不在.js文件中,而是在.js.html文件中( .js html只是为了识别 HTML 页面和完整的 JavaScript 脚本/类之间),在<script>标签内,像这样:

MyClass.js.html

<script>
   class MyClass {

      // Your code here..

   }

</script>

然后,如果你想导入你的类,你只需要使用 HTML 导入:

<link rel="import" href="relative/path/to/MyClass.js.html"/>

<script>
   var myClass = new MyClass();
   // Your code here..
</script>

编辑:HTML 导入将被删除

HTML 导入被删除,有利于 ES6 模块。 您应该使用 ES6 模块。

仅适用于 Node.js,这对我来说效果最好!

我在这里尝试了大多数解决方案,但没有一个能帮助我在不改变范围的情况下加载另一个文件。 最后我用了这个。 这保留了范围和一切。 它与您的代码在这一点上一样好。

const fs = require('fs');
eval(fs.readFileSync('file.js') + '');

我创建了一个函数,允许您使用与 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);
}

最好使用jQuery方式。 要延迟就绪事件,首先调用$.holdReady(true) 示例(来源):

$.holdReady(true);
$.getScript("myplugin.js", function() {
    $.holdReady(false);
});

我基本上是这样做的,创建一个新元素并将其附加到头部:

var x = document.createElement('script');
x.src = 'http://example.com/test.js';
document.getElementsByTagName("head")[0].appendChild(x);

jQuery中:

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // Script is now loaded and executed.
    // Put your dependent JavaScript code here.
});

这是一个Grunt插件,允许您使用@import "path/to/file.js"; 任何文件中的语法,包括 JavaScript 文件。 它可以与 uglify 或 watch 或任何其他插件配对。

可以使用 npm install 安装: https ://npmjs.org/package/grunt-import

我需要异步加载 JavaScript 文件数组并在最后进行回调。 基本上我最好的方法如下:

// Load a JavaScript file from other JavaScript file
function loadScript(urlPack, callback) {
    var url = urlPack.shift();
    var subCallback;

    if (urlPack.length == 0) subCallback = callback;
    else subCallback = function () {
        console.log("Log script: " + new Date().getTime());
        loadScript(urlPack, 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 = subCallback;
    script.onload = subCallback;

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

例子:

loadScript(
[
    "js/DataTable/jquery.dataTables.js",
    "js/DataTable/dataTables.bootstrap.js",
    "js/DataTable/dataTables.buttons.min.js",
    "js/DataTable/dataTables.colReorder.min.js",
    "js/DataTable/dataTables.fixedHeader.min.js",
    "js/DataTable/buttons.bootstrap.min.js",
    "js/DataTable/buttons.colVis.min.js",
    "js/DataTable/buttons.html5.min.js"
], function() { gpLoad(params); });

在第一个脚本完全加载之前,第二个脚本不会加载,所以......

结果:

结果

这可能是另一种方式!

在 Node.js 中,您可以像下面的代码所示那样做!

子.js

    module.exports = {
      log: function(string) {
        if(console) console.log(string);
      }
      mylog: function(){
        console.log('just for log test!');
      }
    }

main.js

    const mylog = require('./sub');

    mylog.log('Hurray, it works! :)');
    mylog.mylog();

参考

http://requirejs.org/docs/node.html

如果你使用 Angular,那么插件模块$ocLazyLoad可以帮助你做到这一点。

以下是其文档中的一些引用:

使用多个文件加载一个或多个模块和组件:

 $ocLazyLoad.load(['testModule.js', 'testModuleCtrl.js', 'testModuleService.js']);

加载具有多个文件的一个或多个模块,并在必要时指定类型: 注意:当使用 requireJS 样式格式(例如以 js! 开头)时,不要指定文件扩展名。 使用其中一种。

 $ocLazyLoad.load([ 'testModule.js', {type: 'css', path: 'testModuleCtrl'}, {type: 'html', path: 'testModuleCtrl.html'}, {type: 'js', path: 'testModuleCtrl'}, 'js!testModuleService', 'less!testModuleLessFile' ]);

您可以加载外部库(不是角度):

 $ocLazyLoad.load(['testModule.js', 'bower_components/bootstrap/dist/js/bootstrap.js', 'anotherModule.js']);

您还可以加载 css 和模板文件:

 $ocLazyLoad.load([ 'bower_components/bootstrap/dist/js/bootstrap.js', 'bower_components/bootstrap/dist/css/bootstrap.css', 'partials/template1.html' ]);

使用 ES6 导入和导出与 Node.js 一起使用的模块

使用.mjs扩展名而不是.js命名文件

创建文件

touch main.mjs lib.mjs

main.js

import { add } from './lib.mjs';
console.log(add(40, 2));

库.mjs

export let add = (x,y) => {
  return x + y
}

node --experimental-modules main.js

在过去的一个项目中,我使用ajile导入可重用的 JavaScript 文件取得了相当大的成功。 我一直希望 JavaScript 本身有一个内置的功能。

不要忘记查看LAB.js

<script type="text/javascript">
       $LAB
       .script("jquery-1.8.3.js").wait()
       .script("scripts/clientscript.js");      
</script>

现在,我可能完全被误导了,但这是我最近开始做的事情... 用回车符开始和结束您的 JavaScript 文件,放入 PHP 脚本,然后再添加一个回车符。 PHP 会忽略 JavaScript 注释“//”,因此无论如何都会包含在内。 回车的目的是使包含的 JavaScript 的第一行不被注释掉。

从技术上讲,您不需要评论,但它会在Dreamweaver中发布令我恼火的错误。 如果您在不发布错误的 IDE 中编写脚本,则不需要注释或回车。

\n
//<?php require_once("path/to/javascript/dependency.js"); ?>

function myFunction(){
    // stuff
}
\n
var s=["Hscript.js","checkRobert.js","Hscript.js"];
for(i=0;i<s.length;i++){
  var script=document.createElement("script");
  script.type="text/javascript";
  script.src=s[i];
  document.getElementsByTagName("head")[0].appendChild(script)
};

这很简单。 假设您要在文件 B.js 中导入文件 A.js。

现在可以确定您已将 B.js 链接到 HTML 文件中,然后只需在该 HTML 文件中将 A.js 链接到 B.js 之前。 然后 A.js 的公共变量将在 B.js 内部可用

这不需要复杂的答案。

我用另一种方法尝试了这个问题,

脚本导入的顺序,在这里不起作用。

索引.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Trials</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="main.js"></script>
    <script src="scriptA.js"></script>
</head>

<body>
<h3>testing js in js (check console logs)</h3>
<button onclick="fnClick()">TEST</button>
</body>

</html>

main.js

function fnClick() {
  console.log('From\tAAAAA');
  var pro = myExpo.hello();
  console.log(pro);
}

脚本A.js

myExpo = {
    hello: function () {
        console.log('From\tBBBBB');
        return "Hello";
    }
}

结果

From    AAAAA
From    BBBBB
Hello
Step 1: Declare the function in another class.

    export const myreport = (value) => {
    color = value.color;
    name = value.name;
    
    var mytext = name + " | " + color;
    return mytext;
    }

Step 2:- Import that function which is needed to be used.

    import {myreport} from '../../Test'

Step 3:- Use that function.

let val = { color: "red", name: "error" }
var resultText = myreport(val)
console.log("resultText :- ", resultText)

不能导入,但可以参考。

PhpShtorm IDE。 要引用,在一个.js文件到另一个.js ,只需将其添加到文件的顶部:

<reference path="../js/file.js" />

当然,您应该使用自己的 PATH 指向 JavaScript 文件。

我不知道它是否适用于其他 IDE。 可能是的,试试吧。 它也应该在 Visual Studio 中工作。

另一种方法是使用 HTML 导入。 这些可以包含脚本引用以及样式表引用。

您可以只链接一个 HTML 文件,例如

<link rel="import" href="vendorScripts.html"/>

vendorScripts.html文件中,您可以包含您的脚本引用,例如:

<script src="scripts/vendors/jquery.js"></script>
<script src="scripts/vendors/bootstrap.js"></script>
<script src="scripts/vendors/angular.js"></script>
<script src="scripts/vendors/angular-route.js"></script>

查看HTML Imports了解更多详细信息。

不幸的是,这只适用于 Chrome。

按顺序动态加载多个脚本

如果您只加载一个脚本或者您不关心多个脚本的加载顺序,则上述功能可以正常工作。 如果你有一些脚本依赖于其他的,你需要使用Promise来指定加载的顺序。 这背后的原因是 Javascript 异步加载脚本和图像等资源。 加载顺序不依赖于异步调用的顺序,这意味着即使在调用dynamicallyLoadScript("scrip1")之前调用 dynamicLoadScript dynamicallyLoadScript("scrip2") "scrip1") 也不能保证 script1 在 script2 之前加载

所以这是另一个版本的动态加载脚本,它保证加载顺序:

// Based on: https://javascript.info/promise-basics#example-loadscript
function dynamicallyLoadScript(url) {
        return new Promise(function(resolve, reject) {
        var script = document.createElement("script");
        script.src = url;
        script.onload = resolve;
        script.onerror = () => reject(new Error(`Error when loading ${url}!`));
        document.body.appendChild(script);
    });

有关 Promises 的更多信息,请参阅这个出色的页面

这个新的 dynamicLoadScript 的使用非常简单:

dynamicallyLoadScript("script1.js")
.then(() => dynamicallyLoadScript("script2.js"))
.then(() => dynamicallyLoadScript("script3.js"))
.then(() => dynamicallyLoadScript("script4.js"))
.then(() => dynamicallyLoadScript("script5.js"))
//...

现在脚本按 script1.js、script2.js、script3.js 等顺序加载。

脚本加载后运行依赖代码

此外,您可以在加载脚本后立即运行使用脚本的代码。 只需在加载脚本后添加另一个.then

dynamicallyLoadScript("script1.js")
.then(() => dynamicallyLoadScript("script2.js"))
.then(() => foo()) // foo can be a function defined in either script1, script2
.then(() => dynamicallyLoadScript("script3.js"))
.then(() => {
     if (var1){ // var1 can be a global variable defined in either script1, script2, or script3
          bar(var1); // bar can be a function defined in either script1, script2, or script3
     } else {
          foo(var1);
     }
})
//more .then chains...

处理加载错误

要显示未处理的承诺拒绝(错误加载脚本等),请将此unhandledrejection事件侦听器放在代码的顶部:

// Based on: https://javascript.info/promise-error-handling#unhandled-rejections
window.addEventListener('unhandledrejection', function(event) {
     // the event object has two special properties:
     console.error(event.promise);// the promise that generated the error
     console.error(event.reason); // the unhandled error object
});

现在,您将收到任何脚本加载错误的通知。


快捷功能

如果您在加载大量脚本后没有立即执行代码,那么这个速记函数可能会派上用场:

function dynamicallyLoadScripts(urls){
        if (urls.length === 0){
            return;
        }
        let promise = dynamicallyLoadScript(urls[0]);
        urls.slice(1).forEach(url => {
            promise = promise.then(() => dynamicallyLoadScript(url));
        });
    }

要使用它,只需传入一个脚本 url 数组,如下所示:

const scriptURLs = ["dist/script1.js", "dist/script2.js", "dist/script3.js"];
dynamicallyLoadScripts(scriptURLs);

脚本将按照它们在数组中出现的顺序加载。

请注意,我们通常使用静态脚本 所以我们希望尽可能多地从缓存中取出。

这样可以节省网络流量并加快登陆速度。

用法

$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
  console.log( textStatus );
});

cache: true选项已添加到 Ajax 方法中。

如果调用时发现有两个或多个脚本占用同一个函数,而我们不能同时包含它们,我们需要通过用户选择来动态地包含它们。

使用$.getScript在 jQuery 中包含另一个文件是可行的,因为 默认情况下不会缓存该脚本。 所以我们可以安全地调用其他脚本。 呼叫可以这样安排:

HTML

<select class="choice">
  <option value="script1" selected>Script-1</option>
  <option value="script2">Script-2</option>
</select>

JavaScript

  $(".choice").change(on_change);

    var url = "https://example.com";
    $.url1 = url + "/script1.js";
    $.url2 = url + "/script2.js";

  function on_change() {
    if ($(".choice").val()=="script1") {
        script1();
    } else {
         script2();
    }

    // script1
    function script1() {
      $.getScript($.url1, function( data, textStatus, jqxhr ) {
          // Execute here
      });
    }

    // script2
    function script2() {
       $.getScript($.url2, function( data, textStatus, jqxhr ) {
          // Execute here
      });
    }

Dan Dascalescu 从 Facebook 的想法中得到的答案对图书馆的一点扩展。

(function() {
var __ = {};
this._ = function(name, callback) {
    if(__[name]==undefined) {
        __[name] = true;
        var firstScript = document.getElementsByTagName('script')[0],
          js = document.createElement('script');
          js.src =  name;
          js.onload = callback;
          firstScript.parentNode.insertBefore(js, firstScript);
    }
}
})();

(new _('https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js', function() {
 snowStorm.snowColor = '#99ccff';
}));
var xxx = require("../lib/your-library.js")

或者

import xxx from "../lib/your-library.js" //get default export
import {specificPart} from '../lib/your-library.js' //get named export
import * as _name from '../lib/your-library.js'  //get full export to alias _name

您可以使用我的loadScript ES 模块来加载 JavaScript 文件。

用法:

在您的 head 标签中,包含以下代码:

<script src="https://raw.githack.com/anhr/loadScriptNodeJS/master/build/loadScript.js"></script>

或者

<script src="https://raw.githack.com/anhr/loadScriptNodeJS/master/build/loadScript.min.js"></script>

现在您可以使用 window.loadScript 来加载您的 JavaScript 文件。

loadScript.async( src, [options] )

异步加载 JavaScript 文件。

src :外部脚本文件的 URL 或脚本文件名数组。

options :以下选项可用

onload: function () The onload event occurs when a script has been loaded. Default is undefined.

onerror: function ( str, e ) The onerror event occurs when an error has been occurred. The default is undefined.

    str: error details

    e: event

appendTo: The node to which the new script will be append. The default is the head node.

例如

loadScript.async( "JavaScript.js",
        {
            onload: function () {

                var str = 'file has been loaded successfully';
                console.log( str );
            },
            onerror: function ( str, e ) {

                console.error( str );
            },
        } );

使用示例

所以这是一个边缘案例。 但是,如果您需要从远程源加载 JavaScript,大多数现代浏览器可能会由于 CORS 或类似原因而阻止您的跨站点请求。 太正常了

<script src="https://another-domain.com/example.js"></script>

不会工作。 并且执行document.createElement('script').src = '...'也不会削减它。 相反,您可以做的是通过标准GET请求将 java 脚本作为资源加载,然后执行以下操作:

<script type="text/javascript">
    var script = document.createElement('script');
    script.type = 'text/javascript';

    let xhr = new XMLHttpRequest();
    xhr.open("GET", 'https://raw.githubusercontent.com/Torxed/slimWebSocket/master/slimWebSocket.js', true);
    xhr.onreadystatechange = function() {
        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
            script.innerHTML = this.responseText; // <-- This one
            document.head.appendChild(script);
        }
    }
    xhr.send();
</script>

通过自己抓取内容,浏览器不会注意到恶意意图并允许您执行请求。 然后将其添加到<script>innerHTML中。 这仍然会导致浏览器(至少在 Chrome 中测试过)解析/执行脚本。

同样,这是一个边缘案例用例。 而且您可能没有向后兼容性或浏览器合规性。 但是有趣/有用的事情要知道。

发出fetch请求并eval结果。

我的通用解决方案取自EdgeS (我创作的)efekt.js.st库。

无耻的插件警报- 我在其他 stackexchange 网络站点上。 这是https://codereview.stackexchange.com/questions/263764/dynamic-load-css-or-script的重新链接。

您将使用什么代码或设计来支持cssscripts的动态加载?

要求

  • 支持promise-await-async包括错误处理
  • 支持一次加载缓存,包括重新加载
  • 支持在headbody或当前script-element中加载
  • 支持加载cssjsmjs模块或其他脚本类型
  • 支持其他标签crossorigin ,如noncecrossorigin
static loadScriptOrStyle(url, options) {
  // provenance :<# **Smallscript EdgeS efekt** `efekt.js.st` github libraries #>
  // returns    :<Promise#onload;onerror>
  // options    :<# `fIgnoreCache`, `fAppendToHead`, `fUrlIsStyle`, `attrs:{}` #>
  const head = document.head; let node = options?.fAppendToBody ? document.body : head;
  const url_loader_cache = document.head.url_loader_cache
    ? head.url_loader_cache
    : (head.url_loader_cache = {script:{},link:{}})
  const kind = (options?.fUrlIsStyle || /\.css(?:(?:\?|#).*)?$/i.test(url))
    ? 'link' : 'script';
  // check already-loaded cache
  if(url_loader_cache[kind][url]) {
    const el = url_loader_cache[kind][url];
    // support `fIgnoreCache` reload-option; should not use on `head`
    if(options?.fIgnoreCache)
      el.remove();
    else
      return(new CustomEvent('cache',{detail:el}));
  }
  // (re)create and record it
  const self = document.currentScript;
  const el = url_loader_cache[kind][url] = document.createElement(kind);
  const append = (!self || options?.fAppendToHead || options?.fAppendToBody)
    ? el => node.appendChild(el)
    : el => self.parentNode.insertBefore(el, self);
  const load = new Promise((resolve, reject) => {
    el.onload  = e => {e.detail = el;resolve(e)};
    el.onerror = e => {e.detail = el;reject(e)};
    // `onload` or `onerror` possibly alter `cache` value
    // throw(new URIError(`The ${url} didn't load correctly.`))
  });
  // configure `module` attr, as appropriate
  if(/\.mjs(?:(?:\?|#).*)?$/i.test(url))
    el.type = 'module'
  // configure other attrs as appropriate (referrer, nonce, etc)
  for(const key in options?.attrs) {el[key] = attrs[key]}
  // trigger it
  if(kind === 'link') el.rel = 'stylesheet', el.href = url; else el.src = url;
  append(el);
  return(load);
}

因此,如果您想要快速、简单...试试这个:

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

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

    head.appendChild(script)
}

就这么简单:

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

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

document.body.appendChild(js);

要在 JavaScript 中导入另一个脚本,请使用import关键字:

import '/src/js/example.js';

// both types of quotes work
import "/src/js/example2.js";

我没有看到一个答案,您可以在文件中创建所有函数和变量的对象,然后将该对象作为参数以在另一个文件中引用它。

例如,您有名为“jsMod.js”、“jsView”和“jsContr.js”的文件:


    //jsMod.js file
    JSMODOBJ = {};
    JSMODOBJ.valueAddition = function(/* element value 1 */ val1,
                                          /* element value 2 */ val2) {
        return val1 + val2;
    }


    //jsView.js file
    JSVIEWOBJ = {};
    JSVIEWOBJ.elementColour = function(/* element id to change colour */ id,
                                          /* css colour classname */ col) {
        document.getElementById(id).className = col;
    }


    //jsContr.js file
    JSCONTROBJ = {};
    var jsMod = JSMODOBJ;
    var jsView = JSVIEWOBJ;

    JSCONTROBJ.changeColourByValue = function (val1, val2, id, clss) {
        if (jsMod.valueAddition(val1,val2) !== 0) {
            jsView.elementColour(id, clss);
        }
    }

然后,您可以通过将scripts回显到 .html 或 .php 文件中来动态设置 .js 文件:

<?php
    echo "<script src = './js/dleafView.js'></script>
        <script src = './js/dleafModule.js'></script>
        <script src = './js/dleafContr.js'></script>";
?>

然后只需在<script type="text/javascript"></script>标记中调用控制函数。 当然,这在开始时会花费很多时间来设置,但从长远来看,它可以节省您的时间。

我以稍微不同的方式使用它,但这种方式也有效。

您还可以使用gulpgulp-concatgulp-typescript/// <reference path=包括:

包.json

{
  "scripts": {
    "gulp": "gulp main"
  },
  "dependencies": {
    "@types/gulp": "^4.0.6",
    "@types/gulp-concat",
    "@types/gulp-typescript",
    "gulp": "^4.0.2",
    "gulp-concat": "^2.6.1",
    "gulp-resolve-dependencies": "^3.0.1",
    "gulp-typescript": "^6.0.0-alpha.1",
    "typescript": "^3.7.3"
  }
}

src/someimport.ts

class SomeClass {
    delay: number;
}

src/main.ts

/// <reference path="./someimport.ts" />

someclass = new SomeClass();
someclass.delay = 1;

这个main的 gulp 任务(在gulpfile.js上)仅针对src/main.js文件,解析其所有/// <reference path=...包含引用。 这些包括被称为Triple-Slash Directives ,它们仅用于编译器工具来组合文件。 在我们的例子中,它们由.pipe(resolveDependencies({和 typescript 本身在检查文件是否缺少类型、变量等时显式使用。

  1. https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
  2. 我什么时候需要三斜杠引用?

如果您想自定义var tsProject = ts.createProject调用而不使用tsconfig.json文件或覆盖其参数,请参阅https://github.com/ivogabe/gulp-typescript#api-overview

gulpfile.js

var gulp = require("gulp");
var concat = require('gulp-concat');
var resolveDependencies = require('gulp-resolve-dependencies');

var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");

gulp.task("main", function() {
  return gulp
    .src(["src/main.ts"])
    .pipe(resolveDependencies({
      pattern: /^\s*\/\/\/\s*<\s*reference\s*path\s*=\s*(?:"|')([^'"\n]+)/gm
    }))
    .on('error', function(err) {
        console.log(err.message);
    })
    .pipe(tsProject())
    .pipe(concat('main.js'))
    .pipe(gulp.dest("build/"));
});

如果您想定位所有类型脚本项目文件,而不仅仅是src/main.ts ,您可以替换它:

  return gulp
    .src(["src/main.ts"])
    .pipe(resolveDependencies({
    ...
// -->
  return tsProject
    .src()
    .pipe(resolveDependencies({
    ...

如果您不想使用typescript ,可以使用这个简化gulpfile.js并从package.json中删除所有typescript包含:

gulpfile.js

var gulp = require("gulp");
var concat = require('gulp-concat');
var resolveDependencies = require('gulp-resolve-dependencies');

gulp.task("main", function() {
  return gulp
    .src(["src/main.js"])
    .pipe(resolveDependencies({
      pattern: /^\s*\/\/\/\s*<\s*reference\s*path\s*=\s*(?:"|')([^'"\n]+)/gm
    }))
    .on('error', function(err) {
        console.log(err.message);
    })
    .pipe(concat('main.js'))
    .pipe(gulp.dest("build/"));
});

包.json

{
  "scripts": {
    "gulp": "gulp main"
  },
  "dependencies": {
    "gulp": "^4.0.2",
    "gulp-concat": "^2.6.1",
    "gulp-resolve-dependencies": "^3.0.1"
  }
}

然后,在运行命令npm run gulp build/main.js文件,其内容如下:

构建/main.js

class SomeClass {
}
/// <reference path="./someimport.ts" />
someclass = new SomeClass();
someclass.delay = 1;

在提供build目录文件之后,这允许我将它与script标记一起包含在浏览器中:

<html>
    <head>
        <script src="main.js"></script>
    </head>
    <body>
        <script type="text/javascript">
            console.log(someclass.delay);
        </script>
    </body>
</html>

相关问题:

  1. https://www.typescriptlang.org/docs/handbook/gulp.html
  2. 我可以在没有 requireJS 的情况下使用打字稿吗?
  3. 需要另一个 JS 文件的主文件的 Gulp 简单连接
  4. 节点上的客户端:未捕获的 ReferenceError:未定义要求
  5. 如何使用 gulp 编译 typescript 浏览器节点模块?
  6. 使用 babel 连接文件
  7. 如何在浏览器中要求 CommonJS 模块?
  8. Browserify有替代品吗?

在 JavaScript 中,可以使用import关键字将一个 JavaScript 文件包含在另一个文件中。 例如,如果你有一个名为myScript.js的文件,你想将它包含在另一个名为main.js的文件中,你可以在main.js中使用以下代码:

import * as myScript from './myScript.js';

这会将所有函数和变量从myScript.js导入到main.js中,让您可以像在main.js本身中定义它们一样使用它们。

有趣的事实:这个答案是由 AI 生成的,我已经检查过它并且有效。

如果你想拥有指向位于不同文件中的所有 javascript 函数的单一链接,你可以使用 php 执行类似的操作:

创建一个 php 文件,它将存储所有 javascript 函数/触发器javascript.php并确保它是一个.php文件:

在你的<head>部分

 <script src="/directory/javascript.php"></script>

假设您有一个名为/functions的文件夹,其中包含所有 javascript 文件。 在您的javascript.php中,创建内容类型为application/javascriptheader ,并使用 php glob包含所有 javascript 文件/脚本,如下所示:

javascript.php

<?php 
header("content-type:application/javascript");
foreach(glob("/functions/*.js") as $filename){include($filename);}
?> 

现在您可以创建单独的 javascript 文件并将它们添加到您的/functions文件夹,或者您可以命名的任何文件夹。 这些将自动包含到javascript.php文件中,该文件实际上是一个功能正常的 js 文件,您可以在<head>部分链接该文件。

在后端,您可以使用 CommonJS 模块。 例如:

//a.js
function func () {
   var result = "OK Bro";
   return result;
}

module.exports = { func };
//b.js
var a = require('./a.js');
console.log(a.func);

但是最简单的解决方案呢? 我很惊讶没有人提到这个,所以我发布它! 使用像 Vite.js 这样的打包工具,然后简单地执行以下操作:

import "./path/to/js/file";

而已! OP 已经要求像“ @import in CSS”这样的东西,这就是那样。 它也不像一些旧方法那样复杂 它至少无疑是对初学者最友好的方法,但我相信非初学者也喜欢它。

要开始使用 Vite 进行 Vanilla JavaScript 项目,只需安装 Node 和 NPM,然后执行以下操作:

npm create vite@latest <your-vanilla-js-app-name> --template vanilla

例如:

npm create vite@latest my-js-app --template vanilla

现在添加此答案开头提到的导入并收工。

顺便说一句:您可能想到的另一件事是命名空间问题,例如,如果您在包含的文件中使用的名称与您在当前文件中已有的名称相似怎么办? 但这就是 JavaScript 的本质,对吧? 这不是此方法特有的问题。 因此,您需要制定单独处理的策略。 如果您想了解更多信息,可以在 Addy Osmani 的博客上找到一篇综合文章:在 JavaScript 中处理全局命名空间的设计模式

您可以只使用 require(); 标签。

例如,如果我有一个要添加到 math.js 的addition.js 模块,我会这样做:

//this is math.js

//vars
let a = 1;
let b = 3;

//start of code
const additionfile = require('addition.js');
window.alert("You added " + a + " and " + b + " together, to get " + additionfile.add(a,b) + "!");

如果你想要addition.js 文件,它看起来像这样

function add(a,b) {
   const sum = a + b;
   return sum;
}

你应该使用这个:

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

简单的!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM