Есть ли в JavaScript что-то похожее на @import
CSS, что позволяет включать файл JavaScript в другой файл JavaScript?
В старых версиях JavaScript не было импорта, включения или требования, поэтому было разработано много разных подходов к этой проблеме.
Но с 2015 года (ES6) в JavaScript появился стандарт модулей ES6 для импорта модулей в Node.js, который также поддерживается большинством современных браузеров .
Для совместимости со старыми браузерами можно использовать инструменты сборки, такие как Webpack и Rollup, и / или инструменты переноса, такие как Babel .
ES6 Модули
Модули ECMAScript (ES6) поддерживаются в Node.js начиная с v8.5, с --experimental-modules
флагом и, как минимум, с Node.js v13.8.0 без флага. Чтобы включить "ESM" (по сравнению с предыдущей системой модулей CommonJS в стиле Node.js ["CJS"]), вы либо используете "type": "module"
в package.json
файле, либо задаете расширение файла .mjs
. (Аналогично, модули, написанные с помощью предыдущего модуля CJS Node.js, могут быть названы, .cjs
если по умолчанию используется ESM.)
Использование 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 в браузерах
Браузеры поддерживают загрузку модулей ECMAScript напрямую (не требуются такие инструменты, как Webpack), начиная с Safari 10.1, Chrome 61, Firefox 60 и Edge 16. Проверьте текущую поддержку в caniuse . Нет необходимости использовать .mjs
расширение Node.js ; браузеры полностью игнорируют расширения файлов в модулях / скриптах.
<script type="module">
import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
hello('world');
</script>
// hello.mjs -- or it could be simply `hello.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 требует
Более старый стиль модуля CJS, все еще широко используемый в Node.js, это module.exports
/require
system.
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"
Существуют и другие способы включения JavaScript внешнего содержимого в браузеры, которые не требуют предварительной обработки.
AJAX Загрузка
Вы можете загрузить дополнительный скрипт с помощью вызова AJAX, а затем использовать его eval
для запуска. Это самый простой способ, но он ограничен вашим доменом из-за модели безопасности песочницы JavaScript. Использование eval
также открывает дверь к ошибкам, взломам и проблемам безопасности.
Загрузка Загрузка
Как и Dynamic Imports, вы можете загружать один или несколько сценариев с помощью fetch
вызова, используя обещания для управления порядком выполнения зависимостей сценариев с помощью библиотеки 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.");
});
Динамическая загрузка скриптов
Вы можете добавить тег HTML с 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: динамическая загрузка скриптов .
Обнаружение, когда скрипт был выполнен
Теперь есть большая проблема, о которой вы должны знать. Это подразумевает, что вы загружаете код удаленно . Современные веб-браузеры загружают файл и продолжают выполнять ваш текущий скрипт, потому что они загружают все асинхронно для повышения производительности. (Это относится как к методу 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);
}
Затем вы пишете код, который хотите использовать ПОСЛЕ того, как скрипт загружается в лямбда-функцию :
var myPrettyCode = function() {
// Here, do whatever you want
};
Затем вы запускаете все это:
loadScript("my_lovely_script.js", myPrettyCode);
Обратите внимание, что скрипт может выполняться после загрузки DOM или раньше, в зависимости от браузера и от того, включена ли строка script.async = false;
. В общем , есть отличная статья о загрузке Javascript, которая обсуждает это.
Слияние / предварительная обработка исходного кода
Как упоминалось в верхней части этого ответа, многие разработчики используют в своих проектах инструменты сборки / переноса, такие как Parcel, Webpack или Babel, что позволяет им использовать предстоящий синтаксис JavaScript, обеспечивать обратную совместимость для старых браузеров, объединять файлы, минимизировать, выполнять разбиение кода и т. д.
onreadystatechange
событие и readyState
свойство). Кроме того, динамическая загрузка сценариев не выигрывает у сканеров с предварительной загрузкой. Рекомендовать эту статью HTML5Rocks: html5rocks.com/en/tutorials/speed/script-loadingМожно динамически генерировать тег 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");
js.onload = callback;
Может быть, вы можете использовать эту функцию, которую я нашел на этой странице Как мне включить файл 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)
}
script.onload = callback;
var
, переменная будет глобальной? Я только что написал этот код 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 .
Вы также можете собрать свои скрипты, используя 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
На самом деле есть способ загрузить файл JavaScript не асинхронно, так что вы можете использовать функции, включенные в ваш недавно загруженный файл, сразу после загрузки, и я думаю, что он работает во всех браузерах.
Вы должны использовать jQuery.append()
на <head>
элемент вашей страницы, то есть:
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
Однако этот метод также имеет проблему: если в импортированном файле JavaScript возникает ошибка, Firebug (а также Firefox Error Console и Chrome Developer Tools также сообщат о своем месте неверно, что является большой проблемой, если вы используете 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
, то hello()
функция вызывается, и вы получите уведомление.
(Этот ответ является ответом на комментарий e-sat).
jQuery.getScript
, чтобы вам не пришлось беспокоиться о написании плагина ...script
элемента в head
заставит его работать асинхронно, если для async
него специально не установлено значение false
. "
, код сломаетсяДругой способ, который, на мой взгляд, намного чище, - это сделать синхронный 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);
}
});
}
Затем вы можете использовать его в своем коде, как если бы вы обычно использовали include:
require("/scripts/subscript.js");
И сможете вызвать функцию из необходимого скрипта в следующей строке:
subscript.doSomethingCool();
async: false
предположительно устарел. Не то! Как говорится в вашей цитате, только материал, связанный с jqXHR. Я пришел к этому вопросу, потому что искал простой способ поддерживать коллекцию полезных плагинов JavaScript. Увидев некоторые решения здесь, я придумал это:
Настройте файл с именем «plugins.js» (или extensions.js или все, что вы хотите). Храните ваши файлы плагинов вместе с этим одним основным файлом.
У 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>');
});
- Вручную вызовите только один файл в вашей голове:
<script src="js/plugins/plugins.js"></script>
НО:
Несмотря на то, что все плагины вставляются в тег head так, как они должны, они не всегда запускаются браузером, когда вы нажимаете на страницу или обновляете.
Я обнаружил, что более надежно просто писать теги сценария в PHP include. Вы должны написать это только один раз, и это такая же работа, как вызов плагина с использованием JavaScript.
Я создал функцию, которая позволит вам использовать подобное словоблудие в 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);
}
В прошлом проекте я довольно успешно использовал ajile для импорта многократно используемых файлов JavaScript. Я всегда хотел, чтобы была функция для этого, встроенная в сам JavaScript.
Или вместо включения во время выполнения используйте сценарий для объединения перед загрузкой.
Я использую Звездочки (я не знаю, есть ли другие). Вы строите свой код JavaScript в отдельных файлах и включаете комментарии, которые обрабатываются механизмом Sprockets, как и включенные. Для разработки вы можете включить файлы последовательно, а затем для производства, чтобы объединить их ...
Смотрите также:
Если кто-то ищет что-то более продвинутое, попробуйте RequireJS . Вы получите дополнительные преимущества, такие как управление зависимостями, улучшенный параллелизм и избежание дублирования (то есть получение сценария более одного раза).
Вы можете записать свои файлы JavaScript в «модули», а затем ссылаться на них как на зависимости в других скриптах. Или вы можете использовать RequireJS как простое решение «иди и получи этот скрипт».
Пример:
Определите зависимости как модули:
некоторые-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
});
creation.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 README:
RequireJS загружает простые файлы JavaScript, а также более определенные модули. Он оптимизирован для использования в браузере, в том числе в Web Worker, но может использоваться в других средах JavaScript, таких как Rhino и Node. Он реализует API асинхронного модуля.
RequireJS использует простые теги сценариев для загрузки модулей / файлов, поэтому он должен обеспечивать легкую отладку. Его можно использовать просто для загрузки существующих файлов JavaScript, поэтому вы можете добавить его в существующий проект без необходимости переписывать файлы JavaScript.
...
Есть хорошие новости для вас. Очень скоро вы сможете легко загрузить код JavaScript. Это станет стандартным способом импорта модулей кода JavaScript и станет частью самого ядра JavaScript.
Вам просто нужно написать, import cond from 'cond.js';
чтобы загрузить макрос cond
из файла cond.js
.
Таким образом, вам не нужно полагаться на какую-либо инфраструктуру JavaScript и не нужно явно делать вызовы Ajax .
Ссылаться на:
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
body
он еще не существует или не может быть изменен. Также это помогает объяснить ответы. getScript
будет запущен «после того, как скрипт был загружен, но не обязательно выполнен». Не забудьте проверить LAB.js !
<script type="text/javascript">
$LAB
.script("jquery-1.8.3.js").wait()
.script("scripts/clientscript.js");
</script>
jQuery.getScript()
, которые стабильны и находятся в постоянном развитии. Возможно, я полностью ошибаюсь, но вот что я недавно начал делать ... Запустите и завершите ваши файлы JavaScript с помощью возврата каретки, вставьте в PHP-скрипт, а затем еще один возврат каретки. Комментарий JavaScript "//" игнорируется PHP, поэтому включение происходит в любом случае. Целью возврата каретки является то, что первая строка вашего включенного 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)
};
Это должно сделать:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
eval
то , что случилось с ним. По словам Крокфорда , « eval
это зло. Эта eval
функция - наиболее часто используемая функция JavaScript. Избегайте ее. У eval
нее есть псевдонимы. Не используйте Function
конструктор. Не передавайте строки в setTimeout
или setInterval
». Если вы еще не читали его «JavaScript: Хорошие части», то выходите и делайте это прямо сейчас. Вы будете не пожалеете об этом. http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)Я написал простой модуль, который автоматизирует работу по импорту / включению скриптов модуля в 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);
};
Мой обычный метод:
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 (состояние загружаемого содержимого) меняется на «загружен».
Большинство представленных здесь решений предполагают динамическую загрузку. Вместо этого я искал компилятор, который собирает все зависимые файлы в один выходной файл. Так же, как препроцессоры Less / Sass работают с @import
правилом CSS . Поскольку я не нашел ничего приличного в этом роде, я написал простой инструмент для решения проблемы.
Итак, вот компилятор https://github.com/dsheiko/jsic , который $import("file-path")
надежно заменяет запрошенное содержимое файла. Вот соответствующий плагин Grunt : https://github.com/dsheiko/grunt-jsic .
В главной ветви jQuery они просто объединяют атомарные исходные файлы в один, начиная с intro.js
и заканчивая outtro.js
. Это меня не устраивает, так как не обеспечивает гибкости при разработке исходного кода. Проверьте, как это работает с JSIC:
SRC / main.js
var foo = $import("./Form/Input/Tel");
ЦСИ / Форма / вход / 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 в начало любого другого <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);
})();
Вот плагин Grunt, позволяющий использовать @import "path/to/file.js";
синтаксис в любом файле, включая файлы JavaScript. Это может быть в паре с Uglify или часы или любой другой плагин.
Его можно установить с помощью npm install: https://npmjs.org/package/grunt-import
Если вы хотите в чистом JavaScript, вы можете использовать document.write
.
document.write('<script src="myscript.js" type="text/javascript"></script>');
Если вы используете библиотеку jQuery, вы можете использовать $.getScript
метод.
$.getScript("another_script.js");
Существует также Head.js . Это очень легко иметь дело с:
head.load("js/jquery.min.js",
"js/jquery.someplugin.js",
"js/jquery.someplugin.css", function() {
alert("Everything is ok!");
});
Как видите, это проще, чем Require.js и так же удобно, как $.getScript
метод jQuery . Он также имеет некоторые расширенные функции, такие как условная загрузка, обнаружение функций и многое другое .
Вот синхронная версия без 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
заголовок в своем ответе.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)<script>
тег, а не через XMLHttpRequest
. const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
@import
Синтаксис для достижения CSS-подобный JavaScript импортирования можно с помощью такого инструмента, как смеси через их особый .mix
тип файла (см здесь ). Я предполагаю, что приложение просто использует один из вышеупомянутых методов, хотя я не знаю.
Из документации Mixture по .mix
файлам:
Файлы микширования - это просто файлы .js или .css с .mix. в имени файла. Файл микширования просто расширяет функциональность обычного файла стиля или скрипта и позволяет импортировать и комбинировать.
Вот пример .mix
файла, который объединяет несколько .js
файлов в один:
// 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 теперь бесплатна (не в сети).
ОБНОВЛЕНИЕ : Смесь теперь прекращена. Старые релизы смеси все еще доступны
Если вы используете Web Workers и хотите включить в область работника дополнительные сценарии, другие ответы о добавлении сценариев в head
тег и т. Д. Не будут работать для вас.
К счастью, у Web Workers есть своя собственная importScripts
функция, которая является глобальной функцией в области Web Worker, встроенной в сам браузер, поскольку она является частью спецификации .
Кроме того, в качестве второго наиболее высоко оцененного ответа на ваш вопрос , RequireJS может также обрабатывать включение сценариев внутри Web Worker (вероятно, вызывающего importScripts
себя, но с несколькими другими полезными функциями).
Есть много потенциальных ответов на этот вопрос. Мой ответ, очевидно, основан на ряде из них. Это то, чем я закончил, прочитав все ответы.
Проблема с $.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 , но в настоящее время наблюдается тенденция отклонять синхронные запросы, поэтому вы можете не получить полную поддержку браузера сейчас или в будущем.
Вы можете попытаться использовать $.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;
}
});
Применение:
file3:
var f3obj = "file3";
// Define other stuff
$(function(){
f3obj = "file3docready";
});
File2:
$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
f2obj = "file2docready";
});
File1:
$.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"
});
script
теги?