Питання Як включити файл JavaScript в інший файл JavaScript?


Чи є щось подібне до JavaScript? @import в CSS, що дозволяє включити файл JavaScript в інший файл JavaScript?


4158
2018-06-04 11:59


походження


stackoverflow.com/questions/21294/... - Daniel A. White
@ Даніель, я не хочу використовувати AJAX дзвінок. - Alec Smart
Чому б не оголошувати імпортований файл перед іншим, що його потребує, просто використовуючи замовлений script мітки - falsarella
@Claudiu Це не допомогло б імпорт нічого, але він також повинен працювати. Якщо у вас є JS-файл, який залежить від іншого JS-файлу, просто сповіщайте теги сценаріїв файлів залежностей, тому пізніші вже будуть завантажувати свої залежності. Якщо у вас є ситуація, коли це не є можливим підходом, відповіді тут повинні бути корисними. - falsarella
яка практична перевага це робити? в будь-якому випадку кодова база, залежна від файлу javascript, не збирається завантажувати і почати роботу в будь-якому випадку вона не завантажена! - Ciasto piekarz


Відповіді:


Старі версії JavaScript не імпортували, не включали або не вимагали, тому було розроблено багато різних підходів до цієї проблеми.

Але останні версії JavaScript мають такі стандарти ES6 модулі імпортувати модулі, хоча це ще не підтримується більшістю браузерів. Багато людей використовують модулі з браузерами будувати і / або переписування інструменти, що дозволяють використовувати новий синтаксис з такими функціями, як модулі.

Модулі ES6

Зверніть увагу, що в даний час підтримка браузера для модулів ES6 не надто велика, але вона є на своєму шляху. Відповідно до це StackOverflow відповідь, вони підтримуються в Chrome 61, Firefox 54 (позаду dom.moduleScripts.enabled встановити в about:config) і 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 система Ви можете використовувати babel перейти, якщо ви хочете import синтаксис

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

The jQuery бібліотека забезпечує функціональність завантаження в одній лінії:

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

Завантаження динамічного сценарію

Ви можете додати тег сценарію з URL-адресою сценарію у HTML. Щоб уникнути накладних витрат jQuery, це ідеальне рішення.

Сценарій може навіть знаходитися на іншому сервері. Крім того, браузер оцінює код. The <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> тег до кінця розділу голови сторінки, де src атрибут встановлюється за URL-адресою, яка дається функції як перший параметр.

Обидва ці рішення обговорюються та ілюструються в Безумство JavaScript: завантаження динамічного сценарію.

Визначення того, коли скрипт був виконаний

Тепер у вас є велика проблема, про яку ви повинні знати. Звідси це означає ви дистанційно завантажуєте код. Сучасні веб-переглядачі завантажують файл і продовжують виконувати ваш поточний скрипт, оскільки вони завантажують все асинхронно для підвищення продуктивності. (Це стосується як методу 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);
}

Потім ви пишете код, який хочете використовувати після того, як сценарій буде завантажений в a лямбда-функція:

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

Тоді ви запустите все це:

loadScript("my_lovely_script.js", myPrettyCode);

Зверніть увагу, що скрипт може виконуватись після завантаження DOM, або раніше, залежно від браузера та того, чи ви включили цю лінію script.async = false;. Є велика стаття про завантаження Javascript в цілому який обговорює це.

Злиття / попередня обробка вихідного коду

Як зазначалося у верхній частині цієї відповіді, багато розробників тепер використовують інструменти для створення / трансляції, такі як WebPack, Babel або Gulp, у своїх проектах, що дозволяє їм краще використовувати новий синтаксис і підтримувати модулі, об'єднувати файли, мінімізувати і т.д.


3586
2018-06-04 12:13



Не всі файли javascript виконуються в браузері. - Michael Paulukonis
Ні, але хтось, який використовує щось настільки ж просунуте, як Rhino, інакше б не запитав це питання. - e-satis
Просто для завершення існує третій спосіб. У певних рішеннях, коли ви керуєте обома файлами javascript, ви можете просто зробити 1 гігантський файл javascript, який поєднує в собі вміст обох файлів. - Toad
Не слід "document.createElement (" my_lovely_script.js ");" в прикладі бути "document.createElement (" script ")"? - Russell Silva
Як eval відкриває двері для хакі, якщо це ваш код, який ви виконуєте? - Vince Panuccio


Якщо хтось шукає щось більш просунуте, спробуйте RequireJS. Ви отримаєте додаткові переваги, такі як керування залежністю, краща паралельність та уникнення дублювання (тобто, витягування сценарію більше одного разу).

Ви можете писати свої JavaScript-файли в "модулі", а потім посилатися на них як на залежності в інших скриптах. Або ви можете використовувати RequireJS як простий "go get this script" рішення.

Приклад:

Визначити залежності як модулі:

деяка залежність.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, від якого залежить деяка залежність.js

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

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

Витяг з GitHub README:

RequireJS завантажує прості файли JavaScript, а також більш певні   модулі. Він оптимізований для використання в браузері, у тому числі в Інтернеті   Працівник, але його можна використовувати в інших середовищах JavaScript, наприклад   Носорога та вузол. Вона реалізує асинхронний модуль API.

RequireJS використовує звичайні скриптові теги для завантаження модулів / файлів, тому це слід   дозволяють легко налагоджувати. Він може бути використаний просто для завантаження існуючих   Файли JavaScript, так що ви можете додати його до існуючого проекту без   Вам доведеться перезаписувати свої файли JavaScript.

...


514
2018-06-07 20:55



+1 для посилання на правильно спосіб зробити це :-) Було б ще краще, якщо б ви включили приклад! - Sean Vieira
@ Сеан за вашою пропозицією - я додав короткий приклад - John Strickler
@aaaidan: Причина MattDmo плюс вона спирається на зовнішню бібліотеку, яка в свою чергу спирається на прийняту відповідь. - David Mulder
Для подолання require.js найновішою буде кутовий js, який є більш стабільним і простим у використанні разом з іншими обов'язковими та багатими функціями HTML. - zeeshan
-1: Ці абстракції - "деяказалежність" - дійсно бідні, а індекси додають до плутанини. Я намагаюся зрозуміти, як виглядає приклад робочого коду. Якщо автор подавав робочий приклад, майже кожен зможе пристосувати та узагальнити його відповідно до його потреб. - Tegiri Nenashi


Там насправді є спосіб завантаження файлу JavaScript ні асинхронно, тому ви можете використовувати функції, що входять до вашого завантаженого файлу відразу після завантаження, і я думаю, що він працює у всіх браузерах.

Ви повинні використовувати jQuery.append()на <head> елемент вашої сторінки, тобто:

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

Проте цей метод також має проблему: якщо в імпортованому файлі JavaScript виникає помилка, Firebug (а також Firefox Error Console і Інструменти розробника Chrome а також) неправильно повідомить про своє місце, що є великою проблемою, якщо ви використовуєте Firebug для відстеження JavaScript помилок дуже багато (я роблю). Firebug просто не знає про нещодавно завантажений файл чомусь, тому, якщо в цьому файлі з'являється помилка, він повідомляє, що це відбулося у вашому основному HTML файл, і у вас виникнуть проблеми з з'ясуванням реальної причини помилки.

Але якщо це не проблема для вас, то цей метод повинен працювати.

Я насправді написав плагін jQuery під назвою $ .import_js () який використовує цей метод:

(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');

Я також зробив простий тест для цього на Приклад.

Вона включає в себе main.js файл у головному HTML, а потім скрипт в main.js використовує $.import_js() імпортувати додатковий файл з назвою included.js, який визначає цю функцію:

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

І відразу після включення included.js, the hello() функція викликається, і ви отримуєте оповіщення.

(Ця відповідь є відповіддю на коментар e-satis).


162
2018-04-28 15:25



Я намагаюся використати цей метод, але не працює для мене, елемент просто не відображається в заголовку тегу. - juanpastas
@юanpastas - використовувати jQuery.getScript, таким чином вам не доведеться турбуватися про написання плагіна ... - MattDMo
Чи дійсно ця методика блокується, поки завантажений та виконаний імпортований сценарій? - Flimm
Хм, відповідно Ця стаття, додавши a script елемент до head примусить його запускатися асинхронно, якщо тільки async спеціально налаштований на false. - Flimm
Чи не повинна мати змінну скрипту кодування html об'єктів? Якщо посилання містить ", код зламається - Soaku


Інший спосіб, що, на мій погляд, набагато чистіший - це зробити синхронний запит 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(); 

134
2017-09-08 18:22



Хороше рішення, до голови входить асинхрон, на жаль, працює рішення ajax. - Matteo Conta
Як згадується хтось інший, requjs.org робить це, а також має попередній компілятор, який об'єднує файли js разом, щоб вони завантажувалися швидше. Ви можете перевірити це. - Ariel
Знайдене я міг би налагодити його, додавши цю директиву в нижній частині файлу для Chrome: // @ sourceURL = view_index.js - Todd Vance
на жаль, async: false зараз не використовується в jQuery. Можливо, у майбутньому вийде, тому я б уникнути. - sqram
@katsh Ми не використовуємо об'єкти jqXHR тут. Ваша пропозиція, здається, не підтримує ваш попередній коментар, що говорить про це async: false нібито застаріла. Це не! Як зазначено у вашій цитаті, тільки пов'язані з jqXHR матеріали є. - Zero3


Для вас є хороші новини. Дуже скоро ви зможете легко завантажувати код JavaScript. Це стане стандартним способом імпортування модулів коду JavaScript і стане частиною самого базового JavaScript.

Вам просто потрібно написати import cond from 'cond.js'; завантажити макрос з іменем cond з файлу cond.js.

Таким чином, вам не доведеться покладатися на будь-які основи JavaScript, і ви не повинні робити це явним чином Ajax дзвінки

Відноситься до:


86
2017-07-03 13:32



вимагати / імпортувати на jsfile було занадто довго в майбутньому. (ІМО). - rwheadon
@rwheadon да, здається жахливо, що це не частина мови! Як люди людям щось робили, це не моє! Я нове до нього, і це здається найгіршим (з багатьох) біт безумства - Jonny Leeds
@ jonny-leeds Навіть без вбудованого модульного завантаження, JavaScript у браузері досить гнучкий, щоб ми могли реалізувати таку бібліотеку, як RequireJS для управління нашим модулем. - Keen
середина 2015 року - все ще не реалізовано в жодному браузері developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - scape
так, ви маєте рацію тепер я починаю відчувати себе погано для цього: (Після того, як він був реалізований у всіх браузерах, це буде відмінною функцією, побудованою в JavaScript. - Imdad


Можна динамічно генерувати тег JavaScript і додати його до HTML-документа зсередини іншого коду JavaScript. Це буде завантажувати цільовий файл 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");

72
2018-06-04 12:02



Це працює, але має серйозні проблеми через асинхронне навантаження. - e-satis
Гм ... яка точно? - Svitlana Maksymchuk
@ e-satis - Насправді, це перевага, синхронізація сценарію буде блокувати. Коні для курсів, але 9 разів у 10 ви хочете не блокувати варіант. - annakata
@Svitlana - елементи скрипта, створені таким чином, є асинхронними. В даний час це можна розглядати як використання лазівки, тому це не може бути майбутнім доказом, я не бачив нічого в жодному стандарті, який пояснює це. - annakata
@ e-satis асинхронний це добре, тому що він не буде заморозити вашу сторінку. Використовуйте зворотний виклик, щоб бути сповіщений, коли це буде зроблено js.onload = callback; - Vitim.us


Заява 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;

58
2018-04-17 01:56



... але не підтримується будь-яким веб-переглядачем на сьогоднішній день, відповідно до таблиці сумісності на сторінці, до якої ви зв'язали. - Zero3
Тепер ви можете написати код ES6 і скомпілювати його з Babel.js (babeljs.io) до будь-якої бажаної поточної модульної системи (CommonJS / AMD / UMD): babeljs.io/docs/usage/modules - Jeremy Harris
@ Zero3 Очевидно, що новий IE (Edge) є єдиним - Julian Avar
Чи існує спосіб зробити це без ES6? Сумісність браузера та ті, у кого немає ES6, вимагає цього. - IamGuest


Можливо, ви можете скористатися цією функцією, яку я знайшов на цій сторінці Як включити файл 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)
}

47
2018-06-04 12:04



Повинно бути корисно додати script.onload = callback; - Vitim.us
@Світлана Максимчук так, якщо я не використовую var, змінна буде глобальною? - Francisco Corrales Morales
@FranciscoCorrales так. - Christopher Chiche
Це закінчується глобально з чи без var :) - Vedran Maricevic.
Це не вдається, якщо сторінка не має head. - Dan Dascalescu


Ось а синхронний версія без 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 заголовок у відповідь.


46
2017-12-11 11:54



Відмінна функція! Завантажує JavaScript до того, як будь-який додатковий JS буде написано після тіла. Дуже важливо при завантаженні декількох скриптів. - tfont
@ heinob: що я можу зробити, щоб він працював на міждоменній мережі? (сценарій завантаження з http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js) - user2284570
@ user2284570: якщо ви є власником зовнішнього домену: встановіть заголовок "allow-origin" у відповіді сервера. Якщо ви не є власником: нічого. Вибачте! Це політика перехресного походження. - heinob
@ user2284570: Я розумію ваш коментар таким чином, що ви не є власником домену, з якого ви хочете завантажити скрипт. У такому випадку ви можете завантажити скрипт лише через вставлений <script> тег, а не через XMLHttpRequest. - heinob
Для тих, хто планує використовувати це в Firefox (скажімо, для сценаріїв imacros), додати цей рядок у верхній частині файлу: const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1"); - Kwestion


Я просто написав цей код JavaScript (використовуючи Прототип за 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.


41
2018-01-23 05:20



jrburke написав це як RequireJS. Гітуб: requirejs.org/docs/requirements.html - Mike Caron
Хіба це не ставить завантажений скрипт поза сферою, де вимагається ()? Схоже, eval () є єдиним способом зробити це в межах області. Чи є ще один спосіб? - trusktr