Есть ли в JavaScript что-то похожее на @import
в CSS, что позволяет вам включать файл JavaScript в другой файл JavaScript?
Как включить файл JavaScript в другой файл JavaScript?
Ответы (68)
В старых версиях JavaScript не было импорта, включения или требования, поэтому было разработано множество различных подходов к этой проблеме.
Но с 2015 года (ES6) JavaScript имеет стандарт модулей ES6 для импорта модулей в Node.js, который также поддерживается большинством современных браузеров.
.Для совместимости со старыми браузерами можно использовать инструменты сборки, такие как Webpack и Rollup и / или инструменты транспиляции, такие как Babel.
Модули ES6
Модули ECMAScript (ES6) поддерживаются в Node.js, начиная с версии 8.5, с флагом --experimental-modules
и, по крайней мере, с Node.js v13.8.0 без флага. Чтобы включить «ESM» (по сравнению с предыдущей модульной системой в стиле CommonJS [«CJS»] в Node.js), вы либо используйте "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. Нет необходимости использовать расширение Node.js .mjs
; браузеры полностью игнорируют расширения файлов в модулях / скриптах.
<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
.
// 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
, используя обещания для управления порядком выполнения для зависимостей сценариев с помощью библиотеки 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: загрузка динамического скрипта.
Обнаружение, когда сценарий был выполнен
Итак, вы должны знать о большой проблеме. Это означает, что вы загружаете код удаленно. Современные веб-браузеры загрузят файл и продолжат выполнение вашего текущего скрипта, потому что они загружают все асинхронно для повышения производительности. (Это относится как к методу 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, обеспечивать обратную совместимость для старых браузеров, объединять файлы , минимизировать, выполнить разделение кода и т. д.
Вы можете просто использовать функцию require(); тег.
Например, если бы у меня был модуль add.js, который я хотел бы добавить в math.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) + "!");
если вам нужен файл add.js, он будет выглядеть примерно так
function add(a,b) {
const sum = a + b;
return sum;
}
Это так просто:
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
Итак, если вы хотите быстро и легко... Попробуйте это:
function include(filename)
{
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
head.appendChild(script)
}
На сервере вы можете использовать модули CommonJS. Например:
//a.js
function func () {}
module.exports = { func };
//b.js
var a = require('./a.js');
console.log(a.func);
Мое общее решение взято из библиотеки efekt.js.st
из EdgeS (автор которого я) .
бесстыдное предупреждение о подключении - я нахожусь на других сайтах сети stackexchange. Это повторная ссылка на
https://codereview.stackexchange.com/questions/263764/dynamic-load-css-or-script
.
Какой код или дизайн вы бы использовали для поддержки динамической загрузки css
и scripts
?
Требования
- поддержка обещание-ожидание-async , включая обработку ошибок
- поддержка однократная загрузка кэширование, включая перезагрузку
- поддерживает нагрузку в
head
,body
или текущуюscript-element
- поддержка нагрузки
css
,js
,mjs
модули или другие типы скриптов - поддерживает другой тег attrs , например
nonce
,crossorigin
и т. Д.
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);
}
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)
Вы также можете использовать gulp
, gulp-concat
, gulp-typescript
с /// <reference path=
включает:
packages.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=...
include. Эти включения известны как Triple-Slash Directives
и используются только инструментами транспилятора для объединения файлов. В нашем случае они явно используются .pipe(resolveDependencies({
и самим машинописным текстом при проверке файла на отсутствие типов, переменных и т. Д.
- https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
- Когда мне нужна ссылка на тройную косую черту?
Обратитесь к https://github.com/ivogabe/gulp-typescript#api-overview, если вы хотите настроить вызов var tsProject = ts.createProject
и не использовать файл tsconfig.json
или переопределить его параметры.
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
и удалить все typescript
из package.json
:
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/"));
});
packages.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
со следующим содержимым:
build/main.js
class SomeClass {
}
/// <reference path="./someimport.ts" />
someclass = new SomeClass();
someclass.delay = 1;
Что позволяет мне включить его в браузер с тегом script
после обслуживания файлов каталога build
:
<html>
<head>
<script src="main.js"></script>
</head>
<body>
<script type="text/javascript">
console.log(someclass.delay);
</script>
</body>
</html>
Связанные вопросы:
- https://www.typescriptlang.org/docs/handbook/gulp.html
- Могу ли я использовать машинописный текст без requireJS?
- Gulp простое объединение основного файла, для которого требуется другой файл JS
- Клиент на узле: неперехваченная ошибка ReferenceError: требование не определено
- Как можно скомпилировать модули узла браузера машинописного текста с помощью gulp?
- Объедините файлы с помощью babel
- Как требовать модули CommonJS в браузере?
- Есть ли альтернатива Browserify?
Я не видел ответа, в соответствии с которым вы создаете объект всех функций и переменных в файле, а затем делаете этот объект аргументом для ссылки на него в другом файле.
Например, у вас есть файлы с именами '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);
}
}
Затем вы можете установить файлы .js динамически, вставив scripts
в свой файл .html или .php:
<?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>
. Конечно, вначале это займет много времени, но в конечном итоге это сэкономит ваше время.
Я использую это немного по-другому, но этот способ тоже работает.
Итак, это крайний случай. Но если вам нужно загрузить JavaScript из удаленного источника, большинство современных браузеров могут блокировать ваши межсайтовые запросы из-за CORS или чего-то подобного. Так нормально
<script src="https://another-domain.com/example.js"></script>
Не сработает. И выполнение document.createElement('script').src = '...'
тоже не поможет. Вместо этого вы могли бы загрузить java-скрипт как ресурс через стандартный запрос GET
и сделать следующее:
<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) анализировать / выполнять скрипт.
Опять же, это крайний вариант использования. И, вероятно, у вас не будет обратной совместимости или совместимости с браузером. Но забавная / полезная вещь, о которой нужно знать.
Модули 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";
}
Рабочий пример находится здесь.
Небольшое расширение библиотеки из , ответ Дэна Даскалеску взят из идеи 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';
}));
Вы можете использовать мой модуль 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, [параметры])
Асинхронная загрузка файла 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 );
},
} );
Динамическая загрузка нескольких скриптов по порядку
Вышеупомянутая функция отлично работает, если вы загружаете только один скрипт или вам не важен порядок загрузки нескольких скриптов. Если у вас есть сценарии, которые зависят от других, вам нужно использовать Promise, чтобы указать порядок загрузки. Причина в том, что Javascript загружает ресурсы, такие как скрипты и изображения, асинхронно. Последовательность загрузки не зависит от последовательности асинхронных вызовов, то есть script1 не будет гарантированно загружаться до script2, даже если вы вызовете dynamicallyLoadScript("scrip1")
перед вызовом dynamicallyLoadScript("scrip2")
Итак, вот еще одна версия dynamicLoadScript, которая гарантирует порядок загрузки:
// 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);
});
Подробнее об обещаниях см. на этой отличной странице.
Использовать этот новый 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);
Скрипты будут загружены в том порядке, в котором они появляются в массиве.
Это прекрасное решение, и оно очень хорошо объяснено. Браво и спасибо.
Я попытался решить эту проблему с другим подходом,
Порядок импорта скриптов здесь не действует.
index.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);
}
scriptA.js
myExpo = {
hello: function () {
console.log('From\tBBBBB');
return "Hello";
}
}
и результат равен
From AAAAA
From BBBBB
Hello
Есть несколько способов реализовать модули в 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
Импорт и экспорт модулей с использованием ES6, которые работают с Node.js
Называйте файлы с расширением .mjs
вместо .js
Создать файлы
touch main.mjs lib.mjs
main.js
import { add } from './lib.mjs';
console.log(add(40, 2));
lib.mjs
export let add = (x,y) => {
return x + y
}
Выполнить
node --experimental-modules main.js
Только для Node.js у меня это сработало лучше всего!
Я пробовал здесь большинство решений, но ни одно из них не помогло мне просто загрузить другой файл без изменения области действия. Наконец я использовал это. Что сохраняет размах и все такое. Он настолько хорош, насколько хорош ваш код в этой точке.
const fs = require('fs');
eval(fs.readFileSync('file.js') + '');
Почему последний срок? Кажется, это ничего не делает.
readFileSync возвращает буфер. + ''
преобразует это в строку.
Да, есть ...
Продолжайте читать. В ES6 мы можем export
и import
часть или весь файл JavaScript в другой ...
Но подождите, 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>
Есть также атрибуты async и defer , которые я должен здесь упомянуть ...
Примечание: Есть несколько способов выполнения внешнего сценария:
- Если присутствует асинхронный режим: сценарий выполняется асинхронно. с остальной частью страницы (скрипт будет выполняться, пока страница продолжает синтаксический анализ)
- Если асинхронный режим отсутствует и отложено присутствует: сценарий выполняется, когда страница завершена. синтаксический анализ
- Если ни async, ни defer не присутствуют: сценарий извлекается и выполняется немедленно, прежде чем браузер продолжит работу разбор страницы
Если вы обнаружите, что два или более скрипта выполняют одну и ту же функцию при их вызове, и мы не можем включить их одновременно, нам нужно сделать это динамически по выбору пользователя.
Включение другого файла в jQuery с использованием $.getScript
работает, поскольку сценарий не будет кэшироваться по умолчанию . Так что мы можем безопасно вызывать другие скрипты. Звонки можно организовать так:
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
});
}
Обратите внимание, что мы обычно используем статические скрипты . Итак, мы хотим быть взяты из кеша как можно больше.
Это экономит сетевой трафик и ускоряет посадку.
Использование
$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
console.log( textStatus );
});
Параметр cache: true был добавлен в метод Ajax.
Хотя эти ответы прекрасны, существует простое «решение», которое существует с тех пор, как существовала загрузка скрипта, и оно охватывает 99,999% случаев использования большинством людей. Просто включите нужный сценарий перед тем, как он требует. Для большинства проектов не требуется много времени, чтобы определить, какие скрипты необходимы и в каком порядке.
<!DOCTYPE HTML>
<html>
<head>
<script src="script1.js"></script>
<script src="script2.js"></script>
</head>
<body></body>
</html>
Если для сценария 2 требуется сценарий 1, это действительно самый простой способ сделать что-то подобное. Я очень удивлен, что никто не поднял этот вопрос, так как это наиболее очевидный и простой ответ, который применим почти в каждом отдельном случае.
Это хороший ответ. Возможно, его пропустили, потому что он не дает прямого ответа на вопрос, но также важно понимать, что «обычно вам не нужно этого делать». Тем более, что другие решения такие беспорядочные.
Но это работает только в веб-браузере? А как насчет автономного модульного тестирования (скажем, под Node.js)?
На современном языке с проверкой того, был ли уже загружен скрипт, это будет:
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 );
});
}
Использование (async / await):
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 => {} );
Это очень хорошо, если вы не хотите связываться с модулями и не хотите использовать функцию обратного вызова, но хотите использовать async
/ await
.
url
необходимо правильно экранировать здесь: `head > script[ src = "${url}" ]`
Все очень просто. Предположим, вы хотите импортировать файл A.js в файл B.js.
Теперь вы уверены, что вы связали B.js в файле HTML, а затем просто свяжите A.js перед B.js в этом файле HTML. Тогда общедоступные переменные A.js будут доступны внутри B.js
Это не требует сложного ответа.
Вот обходной путь для браузеров (не Node.js), использующих импорт HTML.
Во-первых, все классы и сценарии 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.
Если вы используете 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' ]);
Вы можете загружать внешние библиотеки (не angular):
$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' ]);
Другой подход - использовать импорт 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.
К сожалению, это работает только в Chrome.
К сожалению, в ссылке HTML Imports указано, что эта функция устарела и удалена из Chrome - chromestatus.com/feature/5144752345317376
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
Вот, может быть, другой способ!
В Node.js это можно сделать так же, как показано в следующем коде!
sub.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();
ссылки
Вы не можете импортировать, но можете ссылаться.
PhpShtorm IDE. Для справки: из одного файла .js
в другой .js
просто добавьте это в начало файла:
<reference path="../js/file.js" />
Конечно, вы должны использовать свой собственный ПУТЬ к файлу JavaScript.
Я не знаю, будет ли это работать в других IDE. Наверное, да, попробуйте. Это должно работать и в Visual Studio.
У меня есть требование асинхронно загрузить массив файлов 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); });
Второй сценарий не загрузится, пока первый не будет полностью загружен, и поэтому ...
Результаты:
В основном я делаю это следующим образом: создаю новый элемент и прикрепляю его к заголовку:
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.
});
Если вы намерены загрузить файл JavaScript с использованием функций из импортированного / включенного файла , вы также можете определить глобальный объект и установить функции как элементы объекта. Например:
global.js
A = {};
file1.js
A.func1 = function() {
console.log("func1");
}
file2.js
A.func2 = function() {
console.log("func2");
}
main.js
A.func1();
A.func2();
Вам просто нужно быть осторожным, когда вы включаете скрипты в HTML-файл. Порядок должен быть таким, как показано ниже:
<head>
<script type="text/javascript" src="global.js"></script>
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
Это не лучшая идея, если у вас много отдельных файлов; чем больше файлов вы создадите, тем больше запросов будет отправлено от клиента, что удлиняет загрузку и также может повлиять на SEO страницы.
У меня была простая проблема, но ответы на этот вопрос меня сбили с толку.
Мне пришлось использовать переменную (myVar1), определенную в одном файле JavaScript (myvariables.js), в другом файле JavaScript (main.js).
Для этого я сделал следующее:
Загрузил код JavaScript в файл HTML в правильном порядке, сначала 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.
Это спасло мне день. Надеюсь, это поможет.
Вот обобщенная версия того, как 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
вместо head
или body
, заключается в том, что некоторые браузеры не создают его, если он отсутствует, но у нас гарантированно есть элемент script
- это один. Подробнее на http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/.
Заявление 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;
Сделайте его красивым, коротким, простым и удобным в обслуживании! :]
// 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]);
}
}
Этот код представляет собой простой краткий функциональный пример того, что может потребоваться дополнительные функциональные возможности для полной поддержки на любой (или данной) платформе.
Объяснение было бы в порядке. Например. в чем идея (принцип работы) и как работает?
На этот вопрос есть много возможных ответов. Мой ответ, очевидно, основан на ряде из них. Это то, к чему я пришел после прочтения всех ответов.
Проблема с $.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
будет выполнен, а не при выполнении обратного вызова, поэтому файл1 все еще продолжает выполнение до загрузки файла3. У этого действительно все та же проблема.
Я решил пойти назад, а не вперед. Спасибо, 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"
});
Если вы используете веб-воркеров и хотите включить дополнительные скрипты в сферу деятельности воркера, другие ответы о добавлении скриптов в тег head
и т. Д. Не будут работать для вас. .
К счастью, Web Workers имеют свою собственную функцию importScripts
, которая является глобальной функцией в области Web Worker, встроенной в сам браузер, поскольку она является частью спецификации.
В качестве альтернативы, как подчеркивает второй по количеству голосов ответ на ваш вопрос, RequireJS также может обрабатывать включение скриптов внутри Web Worker (вероятно, вызывая сам importScripts
, но с некоторыми другими полезными функциями).
Синтаксис @import
для импортирования CSS-подобного JavaScript возможен с использованием такого инструмента, как Mixture, через специальный тип файла .mix
(см. здесь). Я предполагаю, что приложение делает это одним из вышеупомянутых методов.
Из документации Mixture по .mix
файлам:
Файлы микса - это просто файлы .js или .css с расширением .mix. в имени файла. А файл 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, за исключением того, что использую его как интерфейсный инструмент для разработки. Я столкнулся с этим вопросом, когда увидел файл JavaScript .mix
в действии (в одном из шаблонов Mixture) и был немного сбит с толку («вы можете это сделать?» - подумал я про себя). Потом я понял, что это тип файла для конкретного приложения (несколько разочаровал, согласился). Тем не менее, полагал, что эти знания могут быть полезны другим.
Примечание: Выпуск смеси был прекращен 26.07.2016 (после того, как был открыт исходный код 12.04.2015).
Лучше избегать «Обновления» (метаинформации, относящейся к истории изменений этого сообщения). Вместо этого примените его к контенту (не к этому сообщению), например «Смесь была открыта 12 апреля 2015 года, а выпуск этой смеси был прекращен 26 июля 2016 года».
Вот синхронная версия без 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
в своем ответе.
Также существует 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
. Он также имеет некоторые расширенные функции, такие как условная загрузка, обнаружение функций и и многое другое.
Если вам нужен чистый JavaScript, вы можете использовать document.write
.
document.write('<script src="myscript.js" type="text/javascript"></script>');
Если вы используете библиотеку jQuery, вы можете использовать метод $.getScript
.
$.getScript("another_script.js");
Вот плагин Grunt, позволяющий использовать синтаксис @import "path/to/file.js";
в любом файле, включая файлы JavaScript. Его можно использовать в паре с uglify, watch или любым другим плагином.
Его можно установить с помощью npm install: https://npmjs.org/package/grunt-import
Этот сценарий добавит файл 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);
})();
Большинство решений, показанных здесь, подразумевают динамическую загрузку. Вместо этого я искал компилятор, который собирает все зависимые файлы в один выходной файл. То же, что и препроцессоры Less / Sass, работают с at-правилом CSS @import
. Так как я не нашел ничего подобного, я написал простой инструмент, решающий эту проблему.
Итак, вот компилятор, 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");
src/Form/Input/Tel.js
function() {
return {
prop: "",
method: function(){}
}
}
Теперь мы можем запустить компилятор:
node jsic.js src/main.js build/mail.js
И получаем объединенный файл
build/main.js
var foo = function() {
return {
prop: "",
method: function(){}
}
};
Мой обычный метод:
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-адреса. Он устанавливает его в асинхронный режим, поэтому он не блокирует остальную часть кода, но вызывает обратный вызов, когда состояние готовности (состояние загружаемого содержимого) изменяется на «загружено».
Я написал простой модуль, который автоматизирует работу по импорту / включению скриптов модуля в JavaScript. Подробное описание кода см. В сообщении блога Требовать / импортировать / включать модули JavaScript .
// ----- 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);
};
Это должно сделать:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
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)
};
Возможно, я ошибаюсь, но вот что я недавно начал делать ... Начинайте и завершайте свои файлы JavaScript символом возврата каретки, помещайте его в сценарий PHP, после чего следует еще один возврат каретки. Комментарий JavaScript «//» игнорируется PHP, поэтому включение происходит в любом случае. Назначение возврата каретки состоит в том, чтобы первая строка вашего включенного JavaScript не закомментировалась.
Технически комментарий вам не нужен, но он публикует ошибки в Dreamweaver, которые меня раздражают. Если вы пишете сценарий в среде IDE, которая не публикует ошибки, вам не нужны комментарии или символы возврата каретки.
\n
//<?php require_once("path/to/javascript/dependency.js"); ?>
function myFunction(){
// stuff
}
\n
Не забудьте проверить LAB.js!
<script type="text/javascript">
$LAB
.script("jquery-1.8.3.js").wait()
.script("scripts/clientscript.js");
</script>
Лучше использовать способ jQuery. Чтобы отложить событие готовности, сначала позвоните по телефону $.holdReady(true)
.
Пример (источник):
$.holdReady(true);
$.getScript("myplugin.js", function() {
$.holdReady(false);
});
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
Хорошие новости для вас. Очень скоро вы сможете легко загружать код JavaScript. Он станет стандартным способом импорта модулей кода JavaScript и станет частью самого ядра JavaScript.
Вам просто нужно написать import cond from 'cond.js';
, чтобы загрузить макрос с именем cond
из файла cond.js
.
Таким образом, вам не нужно полагаться на какую-либо структуру JavaScript и вам не нужно явно делать вызовы Ajax.
См .:
Семь лет спустя этот ответ не работает: «SyntaxError: объявления импорта могут появляться только на верхнем уровне модуля».
Поделитесь своим кодом, что вы пытаетесь сделать.
Хорошо, вот код, который отлично работает: function Include (jsFilePath) {var js = d.createElement ("script"); js.type = "текст / javascript"; js.src = jsFilePath; d.body.appendChild (js); } // Включают
Если кто-то ищет что-то более продвинутое, попробуйте RequireJS. Вы получите дополнительные преимущества, такие как управление зависимостями, улучшенный параллелизм и избежание дублирования (то есть получения сценария более одного раза).
Вы можете записать свои файлы JavaScript в «модули», а затем ссылаться на них как на зависимости в других сценариях. Или вы можете использовать RequireJS как простое решение «иди и получи этот скрипт».
Пример:
Определите зависимости как модули:
some-dependency.js
define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {
//Your actual script goes here.
//The dependent scripts will be fetched if necessary.
return libraryObject; //For example, jQuery object
});
implementation.js - ваш «основной» файл 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, а также более определенные модули. Он оптимизирован для использования в браузере, в том числе в Интернете. Worker, но его можно использовать в других средах JavaScript, например Rhino и Node. Он реализует API асинхронного модуля.
RequireJS использует простые теги скрипта для загрузки модулей / файлов, поэтому он должен позволяют упростить отладку. Его можно использовать просто для загрузки существующих Файлы JavaScript, поэтому вы можете добавить их в существующий проект без необходимо переписать файлы JavaScript.
...
Или вместо включения во время выполнения используйте сценарий для объединения перед загрузкой.
Я использую Звездочки (не знаю, есть ли другие). Вы создаете свой код JavaScript в отдельных файлах и включаете комментарии, которые обрабатываются механизмом Sprockets как включенные. Для разработки вы можете включать файлы последовательно, а затем для производства, чтобы объединить их ...
См. Также:
В прошлом проекте я добился небольшого успеха, используя ajile для импорта повторно используемых файлов JavaScript. Мне всегда хотелось, чтобы эта функция была встроена в сам 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);
}
Я пришел к этому вопросу, потому что искал простой способ поддерживать коллекцию полезных плагинов JavaScript. Увидев здесь некоторые решения, я пришел к следующему:
-
Создайте файл с именем «plugins.js» (или extension.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>
НО:
Несмотря на то, что все плагины помещаются в тег заголовка так, как они должны, они не всегда запускаются браузером, когда вы щелкаете страницу или обновляете ее.
Я обнаружил, что более надежно просто написать теги сценария во включении PHP. Вам нужно написать его только один раз, и это столько же работы, сколько вызов плагина с помощью JavaScript.
Обратите внимание: если pluginNames содержит специальные символы, это не сработает и может даже привести к уязвимости системы безопасности. Здесь вам нужно использовать правильное экранирование: $('head').append('<script src="js/plugins/' + this + '.js"></script>');
Другой способ, который, на мой взгляд, намного чище, - это сделать синхронный запрос 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 , а не асинхронно, поэтому вы можете использовать функции, включенные в ваш недавно загруженный файл, сразу после его загрузки, и я думаю, что это работает во всех браузерах.
Вам необходимо использовать jQuery.append()
в элементе <head>
вашей страницы, то есть:
$("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, и у вас возникнут проблемы с поиском настоящего файла. причина ошибки.
Но если это не проблема для вас, тогда этот метод должен работать.
На самом деле я написал плагин 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></script').attr('src', 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-satis).
Вы также можете собрать свои скрипты, используя 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 (используя прототип для манипуляции с 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>
Может быть, вы сможете использовать эту функцию, которую я нашел на этой странице Как мне включить файл 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)
}
Можно динамически сгенерировать тег 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");
Я загрузил div динамически, щелкнув меню без загрузки страницы, используя хеш URL. Моя проблема в том, что когда я нажимаю одну и ту же страницу 2/3 раза, js загружается 2/3 раза. вот почему каждое событие происходит многократно. Я хочу проверить файл js, уже загруженный в нижний колонтитул / заголовок, перед добавлением в этот код: var js = document.createElement ("script"); js.type = "текст / javascript"; js.src = jsFilePath; document.body.appendChild (js);
Спасибо за ваш вклад. Есть ли вообще способ вставить скрипт в начало головы?
Вы также можете использовать что-то вроде Gulp (gulpjs.com) для их предварительной обработки с выходом в виде одного вызываемого файла. Например: а) объедините несколько файлов JavaScript в один, б) используйте Babel для обеспечения обратной совместимости, в) minify / uglify для удаления комментариев, пробелов и т. Д. Затем вы не только организовали эти файлы, но и оптимизировали их. а также путем запуска конвейера с возможностью сделать то же самое для других форматов файлов (таких как CSS и изображения).
jakearchibald.com/2017/es-modules-in-browsers кажется мертвой ссылкой.