Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. JavaScript

Модулен подход, при разработката на JavaScript приложенията

by
Length:LongLanguages:

Bulgarian (Български) translation by Mihail Petrov (you can also view the original English article)

Повече от десетилетие JS библиотеки като JQuery бяха тривиалният избор за създаване на браузърни приложения. Благодарение на тях успяхме да се от търсим от тъмното минало на JS проектите пълни с имплементационни несъответствия. Бляскавите лъчи на jQuery разкъсаха мрака на браузърните бъгове и направиха трудният живот на разработчиците, доста по лесен от преди, като им дадоха възможност лесно да извършват мултиплатформени DOM манипулации и AJAX заявки.

Във времето за което говорим, jQuery беше митичен инструмент, чиито възможности и необикновена сила, бяха необходими навсякъде, без да има нужда да се интересуваме откъде всъщност идват те.

Но web разработката, еволюира, програмните интерфейси (API) се подобриха, стандарти започнаха да се имплементират, a това значително подобри скоростта, с която се развива интернет пространството. Това ме навежда на мисълта че големите библиотеки нямат вече място в бъдещето на браузърните технологии, защото сега на дневен ред са модулно-ориентираните среди(module-oriented environment)

Концепцията зад модулите

По своята същност, модулите са нищо повече от енкапсулирана функционалност, която извършва само една задача, но за сметка на това по много добър начин. Примерни действия, които модула може да извършва са например, добавянето на класове към определен елемент или комуникация по мрежата с помощта на AJAX заявки и други.

Модулите могат да се материализират в множество форми и размери, но в общият случай, тяхната основна цел е да бъдат имплементирани в средата за която са нужни и просто да работят. Обикновено, всеки модул би следвало да има някакво базово описание, под формата на документация, свързана с разработката и инсталацията му, както и описание на средата в който се предполага да работи ( браузъра или сървъра)

Модулите за които говорим все по често се превръщат, в неразделна част от проектите, които се разработват, и поради своята природа те са лесни за управление и контрол. Все по успешно оставяме в миналото, дните в който ни се налагаше да добавяме в приложенията си огромни външни библиотеки, който не предоставят необходимата ни гъвкавост, и контрол. За щастие полезни инструменти като JQuery вече са осъзнали този факт, и добавят online инструменти които дават възможност на потребителя да достъпи само тази част от библиотеката, която му е необходима.

Модерните програмни интерфейси, дават изключителна възможност, за имплементация на модулният подход. Като се има предвид, че нивото на нововъведенията в браузърите, рязко се увеличава, всеки следващ ден, можем спокойно да започнем с изграждането на малки, помощни модули, който да ни помагат с множество тривиални задачи от ежедневието ни на разработчици.

Нека се вдъхновим за нашият първи модул

Едни от най-интересните съвременни програмни интерфейси, за мен, винаги е бил classList, който е вдъхновен от библиотеки като jQuery. Сега вече имаме възможност да използваме функционалностите му по естествен начин, възползвайки се от възможностите на браузърите.

classList API-то, съществува от някоя друга година, но въпреки това не голям брой от разработчиците знаят за него. Това разбира се ме вдъхнови да разработя модул, които подпомага, използването му, и естествено, ако се натъкнем а браузър, които не поддържа тази функционалност ще се опитаме да създадем, заобиколен начин за ползването му.

Преди да се захванем за работа, нека разгледаме как jQuery се справят с проблема за добавяне на клас към съществуващ елемент

Когато тази възможност беше имплементирана в програмните интерфейси на браузърите, на разработчиците се даде възможност за ползването на обекта DOMTokenList, който пази в себе си стойностите на полето className. Също така classList API-то, предлага няколко подобни на jQuery метода за работа с DOMTokenList. Ето например как можем да добавим клас, използвайки метода.

Какво можем да научим от този пример? Например, че възможностите на библиотеките който се вграждат в браузъра директно са най-малкото вдъхновяващи и играят голяма роля за бъдещата разработка, на технологията.

Какво ще правим от тук насетне? След като имаме знания за модулите и може би харесахме концепцията за програмният интерфейс classList, е време да си спомним, че не всички браузъри поддържат това нововъведение, все още. Добра идея е да заобиколим липсата му и да на пишем имплементацията, ако такава не е налице.

Нашият първи модул: Apollo.js

Преди около шест месеца, създадох самостоятелен модул за добавяне на класове към елементи. Модула бе писан на чист JavaScript и получи името apollo.js.

Разбира се задачата на модула бе да да имплементира в себе си програмният интерфейс classList и да се дистанцира от ползването на библиотека за извършване на толкова проста и тривиална задача. За съжаление jQuery, не ползваше( и продължава да не ползва) classList API, затова реших, че ще е добра идея да поекспериментирам с тази нова технология.

Нека преминем през процеса по обмисляне и разработка на модула.

Как се ползва classList

Както вече видяхте, classList е изключително елегантна функционалност, и има доста сходен синтаксис с jQuery, което прави прехода между двете доста лесен. Обаче има едно нещо което не ми харесва, и то е че непрекъснато трябва да се обръщаме към обекта classList, за да ползваме неговите методи. Това е едно от нещата които се стремя да премахна, когато написах apollo, като се спрях на следният API дизайн.

Добрият модул за манипулация на съдържание, би трябвало да съдържа методите hasClass, addClass, removeClass и toggleClass. Всички ти ще бъдат включени в нашият модул.

Ако погледнем по-отблизо метода addClass, можете да забележите, че като първи аргумент подадох елемента, с който ще работим. Нека се дистанцираме за секунда от jQuery, където подаваме огромен, обект пълен със всевъзможни данни. В нашият модул ще приемаме като аргумент, обикновен DOM елемент, като начина по който ще го обработим е изцяло във властта на разработчиците. Вторият аргумент, е най-обикновен низ, съдържащ името на произволен клас, който вие си решите.

Ще направим кратък преглед на другите методи, които ще имплементираме, като ще разгледаме техните особености.

Потъркваме ръце и се чудим от къде да започнем. На първо време е добра идея да си създадем обект, който ще съдържа нашите методи и разбира се един външен closure, който ще скрие всичките ни вътрешни променливи, методи и като цяло действия в рамките на нашият модул. Като използваме една (функция който се изпълнява веднага) (IIFE)( immediately-invoked function expression), опаковаме обекта с име Apollo, заедно с няколко допълнителни модула, необходими за имплементацията на classList

Вече имаме работеща абстракция върху classList и може да насочим мислите си към старите версии на браузърите, като осигурим и на тях работеща функционалност. Както вече стана ясно целта на модула apollomodule, е да предостави консистентна и лека самостоятелна имплементация на програмният интерфейс за манипулация на класовете на елементите, независимо от браузъра, който го ползва, затова ще се наложи първо да засечем браузъра който ползваме в момента, чрез откриване на специфични негови възможности (feature detection)

Най-лесният начин за проверка на съществуването на classList е като ползваме следният код

В случая използваме оператора, in, за да оценим наличието на classList, като резултата е булева променлива, която ако е истина, предполага използването на вграденият в браузъра classList,

Ще реализираме поддръжката на стари браузъри, като прочетем стойността на низа, className след което да извъртим цикъл през всички имена, като ги променяме или добавяме нови такива. Библиотеката jQuery ползва доста код, за да реализира това начинание, като интегрира в себе си дълги цикли и сложни структури от данни. Не ми се ще излишно да разширявам нашият модул затова се придържам към ползването на регулярни изрази, който имат за задача да намерят съвпадение в класовете и съответно да направят замяна на съдържанието, като по този начин постигат същият ефект като jQuery с почти никакъв код.

Ето я възможно най-чистата имплементация който мога да измисля.

Нека интегрираме функционалностите в нашият модул като добавяме конструкцията else, за браузъри които не поддържат classList

Работещ пример можете да намерите тук. jsFiddle

Концепцията вече трябва да ви се е изяснила. Нашият модул обаче има още няколко възможности като добавяне на множество класове наведнъж, ако се интересувате можете да я разгледате тук.

В крайна сметка какво постигнахме? Резултата е енкапсулиран самостоятелен модул, който извършва една единствена задача и то добре. Модула е доста лесен за четене и разбиране, като дава възможност за бърза променя и създаване на unit тестове. Можем спокойно да ползваме apollo в проекти които нямат нужда от пълните възможности на jQuery.

AMD и CommonJS

Концепцията за използване на модули никак не е нова, дори напротив, оказва се че ги ползваме непрестанно. Може ми сте наясно че, JavaScript не е вече технология която живее само и единствено в браузъра. Можете да ползвате JS на сървъра и дори в телевизора.

Нека видим какви шаблони можем да ползваме, при разработка и ползването на новите модули за който говорим. Съществуват две концепции, наречени AMD и CommonJS, които ще разгледаме сега.

AMD

AMD е абревиатура за Асинхронна Модулна Дефиниция (Asynchronous Module Definition), представляваща програмен интерфейс, за дефиниране на модули, които да бъдат зареждани асинхронно. AMD може да подпомогне разработката на JS модули, като ги запазва добре енкапсулирани в множество различни файлове.

Технологията включва функцията define, имаща за цел да дефинира самият модул и да го експортира в глобалното пространство като обект. Използването на AMD ни дава възможност също така да използваме произволен модул, като зависимост във вече съществуващ или тепърва разработващ се. Ето и пример който взехме от GitHub проекта на AMD

Може да постигнем нещо такова и в рамките на нашият модул, ако използваме подхода който обсъждахме досега.

CommonJS

Node.js е технология която бързо се разработва през последните няколко години, като води след себе си много интересни шаблони и инструменти. Node.js използва механизъм наречен CommonJS, които използва обекта exprorts, за дефинирането на модули и тяхното съдържание. Нека демонстрираме една наистина базова имплементация на CommonJS

Въпросният код, ще бъде позициониран в свой собствен файл, като за целите на нашият пример го кръстих someModule.js. Спецификацията на CommonJS казва, че за да включим и използваме файла в рамките на друг модул е необходимо да използваме функцията require

Ако сте ползвали системи като Grunt/Gullp, вероятно сте ползвали този шаблон.

В рамките на appolo, е необходимо да реферираме обекта exports вместо обекта window, на последният ред на нашият модул exports.apollo = apollo

Universal Module Definition (UMD)

Концепциите които обсъдихме дотук (AMD и CommonJS) са страхотни подходи, за решаването на нашият проблем, но какво е решението ако искаме да разработим модул, който да работи еднакво добре в рамките на всички познати ни среди (AMD, CommonJS и браузъра)

Първоначално, идеята за организиране на подобен подход беше използването на малко условни конструкции if и else , които ще ни помогнат да намерим правилната среда в която се намираме в момента. В последствие идеята прерасна в универсален подход, който можете да разгледате на този адрес “UMD”. Ето и един пример как се ползва този подход

Доста работи се случват в този код. На първо време подаваме функция като втори аргумент на (самоизпълняващата се функция )(IIFE), която е дефинирана като локална променлива factory, и динамично се задава като AMD модул или глобално към браузъра. Този подход не поддържа CommonJS концепцията, но нищо не ни пречи да го добавим

Магическият ред, който присвоява нашата фабрика към CommonJS концепцията, е module.exports = factory

Ще завършим модула ни с имплементация на UMD, така че да може да се ползва еднакво добре във всички възможни среди (CommonJS, AMD, браузъра). Следващият код включва пълната версия на модула, както и някой допълнения, които не са показвани досега.

Вече нашият модул може да работи в рамките на всички среди, което ни дава изключителна гъвкавост за работа с различи модули.

Тестване

Обикновено е добра идея писането на модули, да бъде акомпанирано с писане на компонентни тестове(unit test), които дават възможност други разработчици да се включат в нашият проект и да изпращат заявки за имплементация на нови възможности. Малките модули често предлагат гъвкав механизъм за актуализация на техните възможности, докато повечето големи библиотеки могат да отнемат доста време за имплементиране на нови възможности или поправяне на разнородни грешки.

ES6 Модули

В следващата итерация на JavaScript ще се радваме на вградена поддръжка на модули.

Нека видим как може да експортираме модули,.

И разбира се как може да включваме модули в нашето приложение

Можете да прочетете повече за ES6 модулите, в тяхната спецификация.

Заключение

Като за финал, нека кажем че беше страхотно изживяване създаването на модул които може да отговори на нуждите на много разработчици независимо от средата в която се използва. Разгледахме различни среди и инструменти, като се запознахме и по добре с техните възможности. Ако някой от модулите не задоволява нуждите ни като разработчици, можем просто да намерим негов заместител или да създадем собствен разбира се, нещо което трудно можем да постигнем при използването на голяма библиотека. Естествено рядко е добра идея да ставаме роби на едно единствено решение.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.