Loading...

Модульдар, киришүү

Модульдар, киришүү

 

Биздин тиркеме өскөн сайын, биз аны адатта "модулдар" деп аталган көптөгөн файлдарга бөлгүбүз келет. Модуль адатта функциялары бар классты же китепкананы камтыйт.

Узак убакыт бою JavaScript тил деңгээлинде модулдун синтаксиси жок болчу. Биринчи сценарийлер кичинекей жана жөнөкөй болгондуктан, бул көйгөй болгон жок. Модулдардын кереги жок болчу.

Бирок убакыттын өтүшү менен скрипттер барган сайын татаалдашып кетти, ошондуктан коомчулук кодду модулдарга уюштуруунун бир нече варианттарын ойлоп тапты. Модулдарды динамикалык жүктөө үчүн китепканалар бар.

Мисалы:

  • AMD эң эски модулдук системалардын бири, башында require.js китепканасы менен ишке ашырылган .
  • CommonJS Node.js сервери үчүн курулган модулдук система.
  • UMD дагы бир модулдук система, ал AMD жана CommonJS менен шайкеш универсалдуу катары сунушталат.

Азыр алардын баары акырындык менен окуянын бир бөлүгү болуп баратат, бирок аларды эски сценарийлерде табууга болот.

Тил деңгээлиндеги модулдук система JavaScript стандартында 2015-жылы пайда болгон жана убакыттын өтүшү менен өнүгүп келген. Учурда аны көпчүлүк браузерлер жана Node.js колдойт. Кийинки, биз аны изилдейбиз.

Модуль деген эмне?

Модуль бул жөн гана файл. Бир скрипт бир модуль болуп саналат.

Модульдер бири-бирин жүктөй алышат жана директиваларды колдоно алышат exportжана importфункцияларды алмашуу үчүн бир модулдун функцияларын башкасынан чакыра алышат:

  • exportучурдагы модулдан тышкары жеткиликтүү болушу керек болгон өзгөрмөлөрдү жана функцияларды белгилейт.
  • importбашка модулдардан функцияларды импорттоого мүмкүндүк берет.

Мисалы, бизде sayHi.jsфункцияны экспорттоочу файл болсо:

@A@// 📁 sayHi.js
export function sayHi(user) {
  alert(`Hello, ${user}!`);
}@A@

…Андан кийин башка файл аны импорттоп, колдоно алат:

@A@// 📁 main.js
import {sayHi} from './sayHi.js';

alert(sayHi); // function...
sayHi('John'); // Hello, John!@A@

Директива модулду учурдагы файлга салыштырмалуу importжолдо жүктөйт жана экспорттолгон функцияны тиешелүү өзгөрмөгө жазат../sayHi.jssayHi

Мисалды браузерде иштетели.

Модульдер бир катар атайын ачкыч сөздөрдү колдогондуктан жана алар бир катар өзгөчөлүктөргө ээ болгондуктан, браузерге скрипт бул <script type="module">.

Бул сыяктуу:

Жыйынтык
say.js
index.html
 
@A@<!doctype html>
<script type="module">
  import {sayHi} from './say.js';

  document.body.innerHTML = sayHi('John');
</script>@A@

Браузер автоматтык түрдө импорттолгон модулду (жана ал импорттогондорду, керек болсо) жүктөп алып иштетет, андан кийин скриптти иштетет.

Модулдар жергиликтүү иштебейт. HTTP(лар) аркылуу гана

Протокол аркылуу веб-баракчаны локалдык түрдө ачууга аракет кылсаңыз , директивалар иштебей турганын file://көрөсүз . Модуль тестирлөө үчүн статикалык серверimport/export сыяктуу жергиликтүү веб серверди колдонуңуз же VS Code үчүн Live Server кеңейтүүсү сыяктуу редакторуңуздун "тирүү сервер" мүмкүнчүлүктөрүн колдонуңуз .

Модулдардын негизги өзгөчөлүктөрү

Модулдар "кадимки" скрипттерден эмнеси менен айырмаланат?

Браузерде да, сервер тарабында да JavaScriptте иштеген негизги мүмкүнчүлүктөр жана функциялар бар.

Ар дайым "катуу колдонуу"

Модулдар ар дайым режимди колдонушат use strict. Мисалы, жарыяланбаган өзгөрмөгө дайындоо катага алып келет.

 
 
@A@<script type="module">
  a = 5; // ошибка
</script>@A@

Өзүнүн өзгөрмө чөйрөсү

Ар бир модулдун өзүнүн масштабы бар. Башкача айтканда, модулда жарыяланган өзгөрмөлөр жана функциялар башка скрипттерде көрүнбөйт.

Төмөнкү мисал 2 скриптти импорттоду жана ичинде жарыяланган hello.jsөзгөрмөнү колдонууга аракет кылат . Натыйжада, ката:useruser.js

Жыйынтык
hello.js
user.js
index.html
 
@A@<!doctype html>
<script type="module" src="user.js"></script>
<script type="module" src="hello.js"></script>@A@

Модулдар тышкы колдонууга арналган функцияларды экспорттоого тийиш. Жана башка модулдар аны импорттой алат.

Ошентип, биз глобалдык өзгөрмөлөргө таянгандын ордуна ага керектүү функцияларды импорттообуз user.jsкерек .hello.js

Туура вариант:

Жыйынтык
hello.js
user.js
index.html
 
@A@import {user} from './user.js';

document.body.innerHTML = user; // John@A@

Браузер ошондой эле ар бир скрипт үчүн көз карандысыз масштабга ээ <script type="module">:

 
 
@A@<script type="module">
  // Переменная доступна только в этом модуле
  let user = "John";
</script>

<script type="module">
  alert(user); // Error: user is not defined
</script>@A@

Эгерде биз жалпы беттеги глобалдык өзгөрмө жасашыбыз керек болсо, анда биз аны объектке ачык ыйгарсак болот window, анда биз өзгөрмөнүн маанисин шилтеме менен ала алабыз window.user. Бирок бул жүйөлүү себепти талап кылган өзгөчөлүк болушу керек.

Модулдагы код импортто бир гана жолу аткарылат

Эгерде бир эле модул бир нече жерде колдонулса, анда анын коду бир гана жолу аткарылат, андан кийин экспорттолгон функция бардык импорттоочуларга өткөрүлүп берилет.

Бул модулдар кантип иштээрин түшүнүү үчүн абдан маанилүү. Келгиле, кээ бир мисалдарды карап көрөлү.

Биринчиден, модулду иштетүүдө терс таасирлер болсо, мисалы билдирүү, модулду бир нече жерде импорттоо аны бир гана жолу көрсөтөт - биринчи импортто:

@A@// 📁 alert.js
alert("Модуль выполнен!");
// Импорт одного и того же модуля в разных файлах

// 📁 1.js
import `./alert.js`; // Модуль выполнен!

// 📁 2.js
import `./alert.js`; // (ничего не покажет)@A@

Иш жүзүндө, модулдук коддун милдети, адатта, инициализациялоо, ички маалымат структураларын түзүү жана бир нерсенин көп жолу колдонулушун кааласак, анда аны экспорттойбуз.

Эми өнүккөн мисал үчүн.

Келгиле, модуль объектти экспорттойт деп элестетип көрөлү:

@A@// 📁 admin.js
export let admin = {
  name: "John"
};@A@

Эгерде модуль бир нече файлдарда импорттолсо, анда модулдун коду бир гана жолу аткарылат, объект adminтүзүлөт жана андан кийин бардык импорттоочуларга өткөрүлүп берилет.

Бардык импорттоочулар бир объектти алышат admin:

@A@// 📁 1.js
import {admin} from './admin.js';
admin.name = "Pete";

// 📁 2.js
import {admin} from './admin.js';
alert(admin.name); // Pete

// Оба файла, 1.js и 2.js, импортируют один и тот же объект
// Изменения, сделанные в 1.js, будут видны в 2.js@A@

Модуль бир гана жолу аткарыларын дагы бир жолу белгилей кетүү керек. Экспорт түзүлүп, андан кийин бардык импорттоочуларга өткөрүлүп берилет, андыктан объектте бир нерсе өзгөрсө admin, анда башка модулдар да бул өзгөрүүлөрдү көрөт.

Бул аракет модулдарды биринчи импорттоодо конфигурациялоого мүмкүндүк берет. Биз анын касиеттерин бир жолу орното алабыз жана келечекте импорттоодо ал конфигурацияланган болот.

Мисалы, модул admin.jsбелгилүү бир функцияны камсыз кылат, бирок эсептик дайындардын объектке adminсырттан берилишин күтөт:

@A@// 📁 admin.js
export let admin = { };

export function sayHi() {
  alert(`Ready to serve, ${admin.name}!`);
}@A@

init.jsКолдонмобуздун биринчи скриптинде биз admin.name. Андан кийин бардыгы, анын ичинде төмөнкүдөн жасалган чалууларды көрөт admin.js:

@A@// 📁 init.js
import {admin} from './admin.js';
admin.name = "Pete";@A@

Башка модул да көрөт admin.name:

@A@// 📁 other.js
import {admin, sayHi} from './admin.js';

alert(admin.name); // Pete

sayHi(); // Ready to serve, Pete!@A@

import.meta

Объект import.metaучурдагы модул жөнүндө маалыматты камтыйт.

мазмуну айлана-чөйрөгө көз каранды. Браузерде ал скриптке шилтемени, же эгер модул HTMLге кыстарылган болсо, учурдагы веб-баракчага шилтемени камтыйт:

 
 
@A@<script type="module">
  alert(import.meta.url); // ссылка на html страницу для встроенного скрипта
</script>@A@

Модулда "бул" аныкталган эмес

Бул анча-мынча өзгөчөлүк, бирок толук болушу үчүн, биз бул жөнүндө сөз кылышыбыз керек.

Жогорку деңгээлдеги модулда thisаныкталбаган .

Модулдук эмес скрипттер менен салыштырыңыз, thisглобалдык объект бар:

 
 
@A@<script>
  alert(this); // window
</script>

<script type="module">
  alert(this); // undefined
</script>@A@

Браузердеги өзгөчөлүктөр

type="module"Кадимки скрипттерге салыштырмалуу скрипттердин бир нече башка серепчи спецификалык өзгөчөлүктөрү бар .

Эгер сиз муну биринчи жолу окуп жатсаңыз, же браузерлерде плагиндерди колдонбосоңуз, бул бөлүмдү азыр өткөрүп жиберсеңиз болот.

Модулдар кийинкиге калтырылды

Модульдер ар дайым кийинкиге калтырылган режимде аткарылат, атрибуту бар скрипттер сыяктуу ( Скрипттер: асинхрондоштуруу, кийинкиге калтырууdefer бөлүмүндө сүрөттөлгөн ). Бул тышкы жана орнотулган скрипт модулдарына да тиешелүү.

Башкача айтканда:

  • сыяктуу тышкы модулдарды жүктөө <script type="module" src="...">, HTML иштетүүгө бөгөт койбойт.
  • модулдар тез жүктөлсө дагы, HTML документинин толук жүктөлүшүн күтүшөт жана андан кийин гана алар аткарылат.
  • скрипттердин салыштырмалуу тартиби сакталат: документте биринчи келген сценарийлер биринчи аткарылат.

Кошумча эффект катары, модулдар ар дайым толук жүктөлгөн HTML баракчасын, анын ичинде астындагы элементтерди көрүшөт.

Мисалы:

 
 
@A@<script type="module">
  alert(typeof button); // object: скрипт может 'видеть' кнопку под ним
  // так как модули являются отложенными, то скрипт начнёт выполнятся только после полной загрузки страницы
</script>@A@

Сравните с обычным скриптом ниже:

@A@<script>
  alert(typeof button); // Ошибка: кнопка не определена, скрипт не видит элементы под ним
  // обычные скрипты запускаются сразу, не дожидаясь полной загрузки страницы
</script>@A@

@A@<button id="button">Кнопка</button>@A@

Көңүл буруңуз: экинчи скрипт биринчисине чейин аткарылат! Ошондуктан, биз биринчи көрөбүз undefined, анан object.

Себеби, модулдар барак толук жүктөлгөндөн кийин иштей баштайт. Кадимки скрипттер дароо иштейт, ошондуктан биз биринчи кезекте кадимки скрипттен кабарды көрөбүз.

Модулдарды колдонууда, модулдар аткарылганга чейин жана JavaScript тиркемеси иштөөгө даяр болгонго чейин HTML барагы браузер тарабынан көрсөтүлөрүн эстен чыгарбашыбыз керек. Кээ бир функциялар иштебей калышы мүмкүн. Келген адамды чаташтырбоо үчүн "жүктөө индикаторун" же башка нерсени коюшубуз керек.

асинхрондук атрибуту ички скрипттерде иштейт

Модулдук эмес скрипттер үчүн атрибут asyncтышкы скрипттерде гана иштейт. Аны менен скрипттер даяр болоор замат иштейт, алар башка скрипттерди же HTML документин күтпөйт.

Модулдар үчүн атрибут asyncкаалаган скрипттерде иштейт.

Мисалы, төмөндөгү скриптте бар async, ошондуктан ал башка скрипттерди күтпөстөн, жүктөлгөндөн кийин дароо аткарылат.

./analytics.jsHTML документи жүктөлө элек болсо же башка скрипттер дагы эле жүктөлүп жатса да, скрипт импорттолот ( жүктөйт) жана ал даяр болгондо дароо иштейт.

Бул модуль эч нерсеге тиешеси жок болгондо абдан пайдалуу, мисалы, эсептегичтер, жарнамалар, окуяны иштетүүчүлөр үчүн.

@A@<!-- загружаются зависимости (analytics.js) и скрипт запускается -->
<!-- модуль не ожидает загрузки документа или других тэгов <script> -->
<script async type="module">
  import {counter} from './analytics.js';

  counter.count();
</script>@A@

Тышкы скрипттер

Атрибуту бар тышкы скрипттердин type="module"эки айырмасы бар:

  1. Бир эле атрибутка ээ тышкы скрипттер srcбир гана жолу иштетилет:

    @A@<!-- скрипт my.js загрузится и будет выполнен только один раз -->
    <script type="module" src="my.js"></script>
    <script type="module" src="my.js"></script>@A@
  2. Башка доменден жүктөлгөн тышкы скрипт CORS аталыштарын көрсөтүүнү талап кылат . Башкача айтканда, эгерде модулдук скрипт башка доменден жүктөлсө, анда алыскы сервер Access-Control-Allow-Originскрипт жүктөөгө уруксат берилгенин көрсөтүүчү башты коюшу керек.

    @A@<!-- another-site.com должен указать заголовок Access-Control-Allow-Origin -->
    <!-- иначе, скрипт не выполнится -->
    <script type="module" src="http://another-site.com/their.js"></script>@A@

    Бул жакшыраак демейки коопсуздукту камсыз кылат.

Жылаңач модулдарга жол берилбейт

Браузерде ал importмодулга салыштырмалуу же абсолюттук жолду камтышы керек. Жолу жок модулдар "жылаңач" модулдар деп аталат. Аларга уруксат берилбейт import.

Мисалы, бул importтуура эмес:

@A@import {sayHi} from 'sayHi'; // Ошибка, "голый" модуль
// путь должен быть, например './sayHi.js' или абсолютный@A@

Башка чөйрөлөр, мисалы, Node.js, жылаңач модулдарга жолдору жок жол берет, анткени алардын мындай модулдар менен кантип иштөө жана аларды кайдан табуу боюнча өз эрежелери бар. Бирок браузерлер азырынча жылаңач модулдарды колдобойт.

Шайкештик, "nomodule"

Эски браузерлер түшүнүшпөйт type="module". Белгисиз атрибуту бар скрипттерге typeжөн гана көңүл бурулбайт. Биз алар үчүн атрибутун колдонуп "резервдик" скрипт түзө алабыз nomodule:

 
 
@A@<script type="module">
  alert("Работает в современных браузерах");
</script>

<script nomodule>
  alert("Современные браузеры понимают оба атрибута - и type=module, и nomodule, поэтому пропускают этот тег script")
  alert("Старые браузеры игнорируют скрипты с неизвестным атрибутом type=module, но выполняют этот.");
</script>@A@

Куруу куралдары

Чыныгы жашоодо браузерлердеги модулдар "чийки" түрүндө сейрек колдонулат. Адатта, биз модулдарды Webpack сыяктуу атайын куралдын жардамы менен бириктирип , анан кодду өндүрүш серверине түртөбүз.

Кранды колдонуунун артыкчылыктарынын бири, ал сизге модулдарды кантип издөөнү көбүрөөк көзөмөлдөөгө мүмкүндүк берет, жылаңач модулдарды жана CSS/HTML модулдары сыяктуу башка көптөгөн "ыңгайлаштырылган" нерселерди колдонууга мүмкүндүк берет.

Ассемблер төмөнкүлөрдү аткарат:

  1. <script type="module">Биз HTMLге киргизе турган "негизги" модулду алат .
  2. Көз карандылыкты талдайт (импорт, импорт жана башкалар)
  3. importБардык модулдар менен бир файлды курат (же бир нече файлдар, муну конфигурациялоого болот), бардыгы иштеши үчүн ассемблерден орнотулган импорт функциясын кайра жазат . HTML/CSS сыяктуу "атайын" модулдун түрлөрү да колдоого алынат.
  4. Процессте коддун башка трансформациялары жана оптималдаштыруулары болушу мүмкүн:
    • Жеткиликсиз код алынып салынды.
    • Пайдаланылбаган экспорт алынып салынат («дарактар ​​титиреп»).
    • consoleжана сыяктуу дизайнга тиешелүү операторлор debuggerалынып салынат.
    • Заманбап JavaScript синтаксисин мурунку стандартка айландырса болот, мисалы, Babel аркылуу окшош функционалдуулук .
    • Натыйжадагы файлды кичирейтсе болот (боштуктарды алып салуу, өзгөрмө аттарын кыскараактары менен алмаштыруу ж.б.).

Эгерде биз куруу куралдарын колдонсок, анда алар модулдарды бир же бир нече файлдарга бириктирип, аларды import/exportөздөрүнүн чалуулары менен алмаштырышат. type="module"Демек, акыркы жыйынды кадимки скрипт катары атрибутсуз туташтырууга болот :

<!-- Предположим, что мы собрали bundle.js, используя например утилиту Webpack -->
<script src="bundle.js"></script>

"Кандай болсо да" модулдары да колдонулушу мүмкүн, ал эми керек болсо коллекторду кийинчерээк конфигурациялоого болот.

Бардыгы

Кыскача айтканда, негизги түшүнүктөр:

  1. Модуль бул файл. Иштөө үчүн import/exportсиз браузерлер үчүн атрибутту көрсөтүшүңүз керек <script type="module">. Модулдар бир катар өзгөчөлүктөргө ээ:
    • Демейки боюнча кийинкиге калтырылган (кийинкиге калтырылган) аткаруу.
    • Async атрибуту саптык скрипттерде иштейт.
    • Тышкы модулдарды башка булактан жүктөө үчүн, ал CORS башын коюшу керек.
    • Кайталануучу тышкы скрипттерге көңүл бурулбайт.
  2. Модулдардын өз чөйрөсү бар, функциялар аркылуу алмашууга болот import/export.
  3. Модулдар ар дайым камтыйт use strict.
  4. Модулдардагы код бир гана жолу аткарылат. Экспорттолуучу функция бир жолу түзүлүп, бардык импорттоочуларга берилет.

Биз модулдарды колдонгондо, ар бир модуль өзүнүн функцияларын ишке ашырат жана аны экспорттойт. Андан кийин биз importаны керектүү жерде түздөн-түз импорттоо үчүн колдонобуз. Браузер скрипттерди автоматтык түрдө жүктөйт жана талдайт.

Чыныгы жашоодо Webpack көбүнчө иштөө жана башка жакшы нерселер үчүн модулдарды бириктирүү үчүн колдонулат.

Кийинки бөлүмдө биз көбүрөөк мисалдарды жана импорт/экспорт параметрлерин көрөбүз.