Нагрузка модуля фактически делит JS на многие модули для легкой разработки и обслуживания. Следовательно, при загрузке многих модулей JS необходимо динамически загружать пользователь.
Прежде чем представить библиотеку загрузки модуля, мы представим метод.
Динамическая загрузка метода JS:
Кода -копия выглядит следующим образом:
function loadjs (url, обратный вызов) {
var node = document.createElement ("script");
Узел [window.addeventListener? "Onload": "onReadyStateChange"] = function () {
if (window.addeventlistener || /загрузки
перезвонить();
node.onreadystatechange = null;
}
}
node.onerror = function () {};
node.src = url;
var head = document.getElementsbytagname ("head") [0];
head.insertbefore (node, head.firstchild); // Перед тем, как вставить его в первый узел головки, предотвратите закрытие метки головки под IE6, и используйте AppenDChild для сообщений об ошибке.
}
Поскольку Situ Zhengmei использовала массовую структуру, которую он написал, чтобы ввести загрузку модулей, наиболее используемым в отрасли требуется. Js и Sea.js. Поэтому я думаю, что у него сильная личность.
Позвольте мне поговорить о процессе загрузки SEA.JS:
Page chaosan.js введен в теге, и объект Seajs будет получен.
Также представьте index.js.
Код index.js выглядит следующим образом:
Кода -копия выглядит следующим образом:
seajs.use (['./ a', 'jquery'], function (a, $) {
var num = aa;
$ ('#J_a'). Text (num);
})
A.JS:
Кода -копия выглядит следующим образом:
Определите (функция (требуется, экспорт, модуль) {
var b = require ('./ b');
var a = function () {
вернуть 1 + parseint (bb ());
}
Exports.a = a;
})
B.JS:
Кода -копия выглядит следующим образом:
Определите (функция (требуется, экспорт, модуль) {
var c = require ('./ c');
var b = function () {
вернуть 2 + parseint (cc ());
}
exports.b = b;
})
C.JS:
Кода -копия выглядит следующим образом:
Определите (функция (требуется, экспорт, модуль) {
var c = function () {
возврат 3;
}
exports.c = c;
})
Из вышесказанного мы видим, что модуль A зависит от B, а B зависит от c.
Когда программа войдет в index.js, SeaJS будет вызвать метод использования.
Кода -копия выглядит следующим образом:
seajs.use = function (ids, обратный вызов) {
GlobalModule._use (IDS, обратный вызов)
}
Описание: Когда GlobalModule инициализируется в SEAJS (когда введен SEA.JS), экземпляр модуля var globalmodule = новый модуль (util.pageuri, status.compiled)
В это время идентификаторы -> ['./a's'jquery'], обратный вызов -> function (a, $) {var num = aa; $ ('#j_a'). Text (num);}
Далее, GlobalModule._USE (IDS, обратный вызов) будет вызван
Кода -копия выглядит следующим образом:
Module.prototype._use = function (ids, callback) {
var uris = resolve (ids, this.uri); // Резолюция ['./a''Jquery']
this._load (uris, function () {// вызовите адрес проанализированного модуля a и jQuery [url1, url2] и вызовите метод _load.
//util.map: пусть все члены данных выполняют указанную функцию за раз и вернуть новый массив, который является результатом выполнения обратного вызова исходного массива
var args = util.map (uris, function (uri) {
вернуть URI? Cachedmodules [uri] ._ compile (): null; // Если существует URL, вызовите метод _compile.
})
if (callback) {callback.apply (null, args)}
})
}
Потому что после вызова метода _load появятся две функции обратного вызова, поэтому мы отмечаем функцию (a, $) {var num = aa; $ ('#j_a'). Text (num);} to callback1,
Установите это.
Метод разрешения заключается в разрешении адреса модуля, поэтому я не буду вдаваться в подробности здесь.
Наконец, Uris in var uris = Resolve (ids, this.uri) была проанализирована в ['http: //localhost/test/seajs/a.js','http: //localhost/test/seajs/lib/juqery/1.7.2/juqery-debug.
И следующее это.
Кода -копия выглядит следующим образом:
// Метод _load () сначала определит, какие файлы ресурсов еще не готовы. Если все файлы ресурсов находятся в состоянии готовности, Callback2 будет выполнен.
// В этом случае мы также будем делать круговые зависимости и выполнять нагрузку на выгруженную JS
Module.prototype._load = function (uris, callback2) {
//util.filter: Пусть все элементы данных выполняют указанную функцию за раз и вернуть новый массив. Массив является участником, который возвращает True после выполнения обратного вызова исходного участника массива.
// UnloadedUris - это массив модулей, которые не скомпилируются
var Unloadeduris = util.filter (uris, function (uri) {
// Возвращает участника, чья функция выполнения логическое значение является истинной, возвращает истину, когда URI существует и не существует во внутренних варенья Cachemodules или он сохраняет значение статуса меньше, чем Status.ready в информации хранилища
// Если значение Status.Ready составляет 4, если оно меньше четырех, возможно, что оно получено и загружается.
вернуть Uri && (! CachedModules [uri] ||
Cachedmodules [uri] .status <status.ready)
});
// Если все модули в URI готовы, выполните обратный вызов и выйдите из корпуса функции (на этот раз будет вызван метод модуля _compile).
var length = UnloadedUris.length
if (длина === 0) {callback2 () return}
// количество не загруженных модулей
var остается = длина
// Создать закрытие и попытаться загружать модули, которые не загружаются
для (var i = 0; i <length; i ++) {
(function (uri) {
// Судите, если информация о хранении URI не существует во внутренней переменной Cachedmodules, создайте экземпляр объекта модуля
var module = cachedmodules [uri] ||
(Cachedmodules [uri] = новый модуль (uri, status.fetching))
// Если значение состояния модуля больше или равно 2, это означает, что модуль был загружен и уже существует локально. В настоящее время выполняется OneFetched ()
// В противном случае вызов (URI, Onfetched) вызывается, чтобы попытаться загрузить файл ресурса. Onload будет запускается после загрузки файла ресурса, а в Onload будет выполнен он -рисованный метод.
module.status> = status.fetched? onfetched (): Fetch (URI, Onfetched)
функция onfetched () {
module = cachedmodules [uri]
// Когда значение состояния модуля больше или равное состоянию.
if (module.status> = status.saved) {
// getPuredEpendencies: Получите массив зависимостей без круговых зависимостей
var deps = getpuredEpendences (модуль)
// Если массив зависимостей не пуст
if (deps.length) {
// снова выполнить метод _load (), пока все зависимости не будут загружены, а обратный вызов не будет выполнен после завершения загрузки всех зависимостей
Module.prototype._load (deps, function () {
CB (модуль)
})
}
// Если массив зависимостей пуст, напрямую выполните CB (модуль)
еще {
CB (модуль)
}
}
// Если приобретение не сбои, например, 404 или не соответствует модульной спецификации
// в этом случае, module.status будет поддерживаться при извлечении или получении
еще {
CB ()
}
}
}) (Unloadeduris [i])
}
// метод CB - выполнить обратный вызов после загрузки всех модулей
Функция cb (module) {
// Если информация о хранении модуля существует, то измените значение состояния в информации о хранилище модуля и измените ее на status.ready
Module && (module.status = status.ready)
// обратные вызовы выполняются только при загрузке всех модулей.
--remain === 0 && callback2 ()
}
}
}
Здесь длина массива UnloadedUris составляет 2, ['http: //localhost/test/seajs/a.js','http: //localhost/test/seajs/lib/juqery/1.7.2/juqery-debug.js'], так что два закрытия с названиями.
Взять http: //localhost/test/seajs/a.js
Далее: Во -первых, будет создан модуль:
Кода -копия выглядит следующим образом:
Cachedmodules ('http: //localhost/test/seajs/a.js') = новый модуль ('http: //localhost/test/seajs/a.js', 1)
module.status> = status.fetched? onfetched (): Fetch (URI, Onfetched)
Поскольку модуль А не загружается в это время, Fetch (URI, Onfetched) будет выполнен следующим образом, то есть Fetch ('http: //localhost/test/seajs/a.js''s.onfetched).
Кода -копия выглядит следующим образом:
Функция Fetch (uri, onfetched) {
// заменить URI на новый адрес запроса в соответствии с правилами на карте
var requesturi = util.parsemap (uri)
// Сначала узнайте, содержится ли запись запросари в полученном списке
if (fetchedList [requesturi]) {
// В настоящее время обновите информацию о хранилище модуля исходного URI для запроса, переопределенного на карте
Cachedmodules [uri] = CachedModules [requesturi]
// Выполнить и возвращать, что означает, что модуль был успешно получен
onfetched ()
Возвращаться
}
// Информация о хранении запроса запроса в списке получения
if (fetchinglist [requesturi]) {
// Добавить обратный вызов, соответствующий URI в списке обратного вызова и возвращает
Callbacklist [requesturi] .push (Onfetched) // Если он получен, вставьте метод обратного вызова этого модуля в массив и верните его.
Возвращаться
}
// Если модули, которые вы пытаетесь получить, не отображаются в FetchedList и FetchingList, добавьте их информацию в список запросов и список вызовов соответственно
fetchinglist [requesturi] = true
Callbacklist [requesturi] = [Onfetched]
// извлекает это
Module._fetch (
Запрос,
function () {
FetchedList [requesturi] = true
// Состояние обновлений модуля
// Если module.status равен status.fectching, измените состояние модуля, чтобы получить
var module = cachedmodules [uri]
if (module.status === status.fetching) {
module.status = status.fetched
}
if (fetchinglist [requesturi]) {
Удалить FetchingList [requesturi]
}
// вызовы Callbacklist Unified выполнение обратных вызовов
if (callbacklist [requesturi]) {
util.foreach (callbacklist [requesturi], function (fn) {
fn () // fn - это метод, соответствующий модулю a.
})
Удалить список обратных вызовов [requesturi]
}
},
config.charset
)
}
Затем будет выполнено module._fetch (), и мы называем функцию обратного вызова здесь как обратный вызов3.
Этот метод должен вызвать метод LoadJS для динамической загрузки файла A.JS. (Поскольку есть и jQuery, будут созданы два новых сценария). Здесь есть вопрос. Если вы создаете скрипт для A и добавите его в голову, вы загрузите файл JS. Однако в Seajs он не загружается. Вместо этого вы будете ждать, пока сценарий для jQuery не будет установлен и добавлен в голову, прежде чем загрузить его (отладчик Google установит точку останова, и он продолжает показывать ожидание ожидания). Это для Мао?
(Рекомендуется здесь: http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff. Я расскажу о дополнительных вопросах здесь. Вы можете знать, зачем нам нужно использовать таблицы, чтобы меньше, потому что, когда таблица отображается, он должен рассчитывать многократно, в то время как Div только для того, чтобы быть тем же временем, что в том же время, что и то же время, в том же время, что в таблице задумал, что в таблице задумался, что в таблице задумал, что в таблице задумал, что в таблице задумался, что в таблице задумал, что в таблице. Прежде чем он будет отображаться, и DIV будет отображаться так же, как и в таблице.
После того, как загрузка будет успешной, она будет проанализирована и выполнена, а метод определения выполняется. Здесь мы сначала выполним код модуля a.
Определить (id, deps, function () {}) анализ метода
Кода -копия выглядит следующим образом:
// Определение определения, идентификатор: идентификатор модуля, DEPS: зависимость модуля, фабрика
Module._define = function (id, deps, factory) {
// Установить зависимости // Если DEPS не является типом массива, заводская функция - это функция
if (! util.isarray (deps) && util.isfunction (factory)) {// Функциональное тело регулярно соответствует требовательной строке и образует массив, чтобы вернуть назначение в DEPS
deps = util.parsedependencies (factory.tostring ())
}
// Установить мета -информацию
var meta = {id: id, зависимости: deps, factory: factory}
if (document.attachevent) {
// Получить узел текущего сценария
var script = util.getCurrentScript ()
// Если узел сценария существует
if (script) {
// Получить оригинальный адрес URI
deariveduri = util.unparsemap (util.getscriptabsolutesrc (script))}
if (! derivivuri) {
util.log ('не удалось вывести URI из интерактивного сценария для:', factory.tostring (), 'Warn')
}
}
.........
}
Определите сначала вынести суждение о заводе, чтобы определить, является ли это функцией (причина в том, что определение также может включать файлы и объекты)
Если это функция, то функция будет получена через Factory.toString (), а зависимость A.JS регулярно сочетается, а зависимость будет сохранена в DEP
Для A.JS его зависимость - B.JS, поэтому DEPS ['./B']
И сохранить информацию A.JS var meta = {id: id, зависимости: deps, factory: factory}
Для A.JS Meta = {id: не определен, зависимости: ['./b'], Factory: function (xxx) {xxx}}
В браузере IE 6-9 вы можете получить путь к запуску JS. Однако в стандартном браузере это невозможно, поэтому вы можете назначить мета -информацию Anonymousmodulemeta = meta.
Затем запустите нагрузку, и будет вызван метод обратного вызова. Этот метод обратного вызова будет изменять значение состояния текущего модуля обратного вызова (A.JS) и установить его на Module.status = status.fetched.
Далее, обратный вызов, соответствующий A.JS в списке Callback Queue Callback, будет выполняться равномерно, то есть.
Обратный метод проверяет, имеет ли модуль A -зависимый модуль. Поскольку А зависит от b, выполните _load () на B.JS, от которого зависит модуль А.
Модуль B будет загружен, а метод определения jQuery будет выполнен в первую очередь. Потому что jQuery не зависит от модулей, после обратного вызова. Обработанные вызовы CB Метод.
Когда B будет реализован в том же процессе, что и A, модуль C будет загружен. Наконец, C, B, модули загружаются и выполняются, и после завершения нагрузки метод CB также будет вызван (сначала C, затем B, затем C)
После того, как все модули будут готовы, будет вызван метод Callback2.
Наконец, обратный вызов называется Back2, и выполняется _compile метод модулей A и jQuery:
Во -первых, составьте модуль A.JS и выполните функцию модуля a. Поскольку в нем требуется (B.JS), он выполнит функцию модуля b.
Функция модуля A запускает выполнение
Функция модуля B начинает выполнять
Функция модуля C запускает выполнение
Выполнение функции модуля C было завершено
Выполнение функции модуля B было завершено
Выполнение функции модуля A было завершено
Наконец, выполните функцию jQuery.
После компиляции выполните Callback1 и вы можете использовать объекты и jQuery.
PS: версия SeaJS была обновлена, и сейчас нет _compile метода. (Все идут, чтобы увидеть это самостоятельно, я тоже хочу это увидеть)
Давайте поговорим о процессе Seajs Module_compile.
Во -первых, сборник A.JS
Кода -копия выглядит следующим образом:
Module.prototype._compile = function () {
126 var module = это
127 // Если модуль был скомпилирован, то возвращает модуль.
128 if (module.status === status.compiled) {
129 return module.exports
130}
133 // 1. Файл модуля составляет 404.
134 // 2. Файл модуля не записан с помощью допустимого формата модуля.
135 // 3. Другие случаи ошибок.
136 // Вот несколько исключений, с которыми нужно иметь дело, а затем вернуть NULL напрямую
137 if (module.status <status.saved &&! Hasmodifiers (module)) {
138 Вернуть NULL
139}
140 // Измените состояние модуля на компиляцию, что означает, что модуль собирается
141 module.status = status.compiling
142
143 // Внутреннее использование модуля является методом, используемым для получения интерфейса, предоставленного другими модулями (называемыми подмодулями) и работы синхронно
144 Функция требуется (id) {
145 // Путь по пути модуля в соответствии с ID
146 var uri = resolve (id, module.uri)
147 // Получить модули из модуля кэша (обратите внимание, что зависимости подмодуля в качестве основного модуля были загружены)
148 var Child = Cachedmodules [uri]
149
150 // Просто верните NULL, когда URI недействителен.
151 // Если ребенок пуст, это может означать только то, что параметр заполняется неправильно, а затем вернуть нулевое напрямую
152 if (! Ребенок) {
153 Вернуть NULL
154}
155
156 // избегает круговых вызовов.
157 // Если статус подмодуля является состоянием.
158 if (child.status === status.compiling) {
159 return child.exports
160}
161 // укажите на модуль, который вызывает текущий модуль во время инициализации. На основании этого свойства вы можете получить стек вызовов при инициализировании модуля.
162 Child.parent = модуль
163 // возвращать модуль. Экспорты составленного ребенка
164 return child._compile ()
165}
166 // Используется внутренне для загрузки модуля асинхронно и выполнить указанный обратный вызов после завершения загрузки.
167 require.async = function (ids, обратный вызов) {
168 module._use (ids, обратный вызов)
169}
170 // Используйте механизм разрешения пути внутри системы модулей для анализа и возврата пути модуля. Эта функция не загружает модуль и только возвращает анализированный абсолютный путь.
171 require.resolve = function (id) {
172 Return Resolve (id, module.uri)
173}
174 // Через это свойство вы можете просмотреть все модули, загруженные системой модулей.
175 // В некоторых случаях, если вам нужно перезагрузить модуль, вы можете получить URI модуля, а затем удалить его информацию с помощью Delete require.cache [uri]. Это будет повторно приобретено в следующий раз, когда вы его будете использовать.
176 require.cache = cachedmodules
177
178 // Требование - это метод получения интерфейсов, предоставленных другими модулями.
179 module.require = требуется
180 // Экспорт - это объект, который обеспечивает интерфейсы модуля снаружи.
181 module.exports = {}
182 var factory = module.factory
183
184 // Когда фабрика является функцией, он представляет конструктор модуля. Выполнив этот метод, вы можете получить интерфейс, предоставленный модулем снаружи.
185 if (util.isfunction (factory)) {
186 compilestack.push (модуль)
187 RuninModuleContext (Factory, Module)
188 compilestack.pop ()
189}
190 // Когда фабрика является нефункциональным типом, таким как объект, строка и т. Д., Интерфейс, представляющий модуль, является объектом, строкой и другими значениями.
191 // Например: определить ({"foo": "bar"});
192 // Например: DEFINE ('Я - шаблон. Мое имя {{name}}.');
193 else if (factory! == не определено) {
194 module.exports = фабрика
195}
196
197 /// Изменить статус модуля на составление, что означает, что модуль был составлен
198 module.status = status.compiled
199 // Выполнение модификации интерфейса модуля через Seajs.modify ()
200 execmodifiers (модуль)
201 return module.exports
202}
Кода -копия выглядит следующим образом:
if (util.isfunction (factory)) {
186 compilestack.push (модуль)
187 RuninModuleContext (Factory, Module)
188 compilestack.pop ()
189}
Вот инициализация Module.export. Метод RunnmoduleContext:
Кода -копия выглядит следующим образом:
// Выполнить код модуля в соответствии с контекстом модуля
489 функция runinmodulecontext (fn, module) {
490 // пройти два параметра, связанные с модулем и самого модуля
491 // Экспорт используется для выставки интерфейсов
492 // потребность используется для получения зависимых модулей (синхронно) (компиляция)
493 var ret = fn (module.require, module.exports, module)
494 // Поддерживает форму интерфейса воздействия возвращаемого значения, например:
495 // return {
496 // fn1: xx
497 //, fn2: xx
498 // ...
499 //}
500 if (ret! == не определен) {
501 module.exports = ret
502}
503}
Выполнить метод функции в A.JS, а затем var b = require ("b.js") будет вызван,
Метод потребования вернет возвращаемое значение метода компиляции B, и в модуле B есть var c = require ('c.js').
В настоящее время будет вызван метод компиляции C, а затем будет вызвана функция C. В C, если объект должен быть выставлен, или возвращается объект C, экспорт модуля C будет экспортировать = c. Или непосредственно module.export = c; Короче говоря, модуль c.export = c будет возвращен в конце; Итак, var c = модуль c.export = c. В модуле B вы можете использовать переменную C, чтобы вызвать методы и свойства объекта C в модуле c.
По аналогии, модуль A может в конечном итоге вызвать свойства и методы объекта B в модуле B.
Независимо от того, какой модуль, если вы используете модуль Module.export = xx, другие модули могут использовать («XX модуль») для вызова различных методов в модуле XX.
Окончательное состояние модуля станет module.status = status.compiled.
Кода -копия выглядит следующим образом:
Module.prototype._use = function (ids, callback) {
var uris = resolve (ids, this.uri); // Резолюция ['./a''Jquery']
this._load (uris, function () {// вызовите адрес проанализированного модуля a и jQuery [url1, url2] и вызовите метод _load.
//util.map: пусть все члены данных выполняют указанную функцию за раз и вернуть новый массив, который является результатом выполнения обратного вызова исходного массива
var args = util.map (uris, function (uri) {
вернуть URI? Cachedmodules [uri] ._ compile (): null; // Если существует URL, вызовите метод _compile.
})
if (callback) {callback.apply (null, args)}
})
}
В это время args = [Module A.Export, Module jQuery.export];
Кода -копия выглядит следующим образом:
seajs.use (['./ a', 'jquery'], function (a, $) {
var num = aa;
$ ('#J_a'). Text (num);
})
В настоящее время A и $ в функции являются модулем A.Export и Module jQuery.export.
Поскольку я сейчас изучаю исходный код jQuery и дизайн jQuery Framework, я делюсь некоторым опытом:
Исходный код jQuery, я прочитал много анализа онлайн, но я больше не могу его читать, когда смотрю на него. Это не очень значимо, поэтому я рекомендую анализ исходного кода Miaowei Classroom.
SITU JavaScript Framework Design's Design's Sit Crastuctor, но после тщательного чтения вы станете старшим инженером-фронт-инженером.
Я предлагаю изучить и использовать Sea.js Yu Bo, в конце концов, это сделано самими китайцами. Новые проекты или реконструкции нашей компании будут выполняться с использованием SEAJS.
Далее находится исходный код, интенсивный чтение модульных ручных сборов и основных магистралей MVC или MVVM Angular. Здесь я надеюсь, что кто -то даст мне предложения о том, какие книги, веб -сайты и видео, чтобы быстро учиться.