Форум

Динамичекий импорт пользовательских модулей

03 декабря 2014 05:36
Здравствуйте.

Поправьте меня, если я ошибаюсь.
На данный момент, если я хочу использовать написанный мною модуль, то я должен ручками тэгом script подключить его к странице, и после этого я уже могу его require(). Но допустим, у меня в приложении 50 таких модулей, в каждом по 5000 строк кода и каждый из которых усердно трудится. Соответственно, мой многострадальный браузер будет смиренно грузить все эти модули независимо от того, будут они использоваться далее или нет. Как следствие - ненужные обращения к серверу, лишний траффик. Для домашних рабочих станций с хорошим каналом это будет не так заметно, но вот на мобильных устройствах скорость оставляет желать лучшего.

Как вы смотрите на то, чтоб модуль загружался браузером всего один раз и только при первом require() этого модуля? Можно было бы ввести соглашение имен, как это сделано в nodejs - все пользовательские модули лежат в определенной директории, имя директории модуля должно совпадать с именем модуля, а исходный текст должен лежать например в module.js…


В принципе, это конечно можно оставить и на откуп разработчикам…. Я это реализовал вот так Код не претендует на эталон, но принцип понятен. Тут есть загвоздка с потоками. Если попытаться импортировать один и тот же модуль через небольшой интервал времени, то этот скрипт поведет себя непредсказуемо т.к. неизвестно, успеет ли загрузиться файл до второго вызова или нет. Должно решиться синхронизацией.


/* Собственно сам импорт */
b4w.register('importer', function(exports, require){
var imported = {};
var modulesDir = '/'; // Ну пусть пока будет корень… =)
exports.import = function(moduleName, callback){
if(!imported[moduleName]){
var s = document.createElement('script');
s.src = modulesDir + moduleName + '.js';
s.onload = function(){
/*Не факт, что это случится ДО второго импорта этого же модуля*/
imported[moduleName] = require(moduleName);
callback(imported[moduleName]);
}
document.body.appendChild(s);
}
else{
/*Вот здесь возникнут проблемы*/
callback(imported[moduleName]);
}
}
});

/* Вызов импорта */
var importer = b4w.require('importer');
var test;
importer.import('test_module', function(module){
test = module;
test.init('hello world');
});



Простите, если несу ересь в массы
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
03 декабря 2014 08:27
UPD Решил проще.

Если файл в данный момент грузится, то запихиваем коллбэк в массив. Если файл уже загружен, то просто вызываем коллбэк. По завершению загрузки файла вызываем все коллбэки успевшие попасть в массив


exports.import = function(moduleName, callback){
if(!imported[moduleName]){
console.log('first import ' + moduleName);
imported[moduleName] = {cb:[callback], status:STATUS_LOADING};
var s = document.createElement('script');
s.src = '/' + moduleName + '.js';
s.onload = function(){
imported[moduleName].status = STATUS_READY;
console.log('imported ' + moduleName);
for(var i = 0; i < imported[moduleName].cb.length; i++)
imported[moduleName].cb[i](require(moduleName));
}
document.body.appendChild(s);
}
else{
if(imported[moduleName].status === STATUS_LOADING){
console.log('pushing while loading ' + moduleName);
imported[moduleName].cb.push(callback);
}
else{
console.log('calling existing ' + moduleName);
callback(require(moduleName))
}
}
}
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
03 декабря 2014 15:54
Привет!

Думаю, стоит оставить реализацию на разработчика приложения, если ему действительно это понадобится.

В большинстве случаев размер кода не настолько большой, чтобы экономить на загрузке. У себя мы используем Google Closure Compiler для компиляции всего движка и отдельных приложений, что уменьшает размер скриптов. Например, модуль src/batch.js из ~4000 строк до/после компиляции будет размером ~140Кб/40Кб, а вся библиотека в сжатом виде весит ~800Кб. Компилятор сейчас есть в составе SDK, но особенности компиляции наших приложений мы в документации не описывали. В будущем, возможно, мы упростим и подробно опишем эту процедуру, чтобы разработчикам приложений было удобно этим пользоваться.

Более того, разумным будет объединение всех скриптов приложения в один подгружаемый js-файл. В случае слабого канала будет проще отправить один запрос на сервер.

Если все-таки приходится грузить действительно много данных, то ваш метод в принципе нормален, когда назначается callback на загрузку. Такой подход используется в загрузчике модулей RequireJS - может, кстати, вам подойти, чтобы не писать свой велосипед.

Ещё, как вариант, вручную прописать всё тегом <script>, добавив атрибут defer или async для модулей, которые будут использоваться отложенно, также добавив для них событие onload. Так исчезнет проблема со временем загрузки, т.к. они будут грузиться асинхронно и не будут блокировать старт приложения, но всё равно останется ненужный трафик.
03 декабря 2014 16:16
Солидарен с вами по всем пунктам. За линк на RequireJS спасибо, ознакомлюсь. Единственное, наверное, что хочу добавить: при подходе "один модуль - один файл", ориентироваться в коде гораздо проще. ИМХО для dev - самое оно. Особенно если приложение большое (у меня вот фантазия богатая, я могу много чего понапридумывать) и код постоянно дописывается\переписывается. А на продакшне, да - единственный склеенный минимизированный файл
Гале подарили мяч, Гале подарили торт, Галю поздравляют все - Галя сделала аборт
03 декабря 2014 22:20
Ответ на сообщение пользователя -Vampire-
Единственное, наверное, что хочу добавить: при подходе "один модуль - один файл", ориентироваться в коде гораздо проще. ИМХО для dev - самое оно. Особенно если приложение большое (у меня вот фантазия богатая, я могу много чего понапридумывать) и код постоянно дописывается\переписывается. А на продакшне, да - единственный склеенный минимизированный файл

Ну, это само собой, я продакшн и имел ввиду .
02 апреля 2015 16:56
Вот пытаюсь назначать интерактивы через NLA script slots, сложно разобраться в правильных последовательностях их назначений и слишком краткое описание по типам слотов и их применении,
всзязи с чем появилась мысль а не эффективней бы была с ними работа через визуальное програмирование в НОД эдиторе если все последовательности и связи и функции НЛА слотов перенести на нодовую структуру то с ними бы в разы было бы проще и логичнее взаимодействовать…на мой взгляд
интересно ваше мнение на этот счет
спасибо
Всех Благ
Роман
02 апреля 2015 17:11
Мы с вами абсолютно согласны, и именно поэтому сейчас у нас идёт работа над собственным нодовым редактором логики.
02 апреля 2015 18:12

Ответ на сообщение пользователя Евгений Родыгин
Мы с вами абсолютно согласны, и именно поэтому сейчас у нас идёт работа над собственным нодовым редактором логики.

круто Больших вам Успехов

а то мне пришлось в свое время освоить TouchDesigner -http://www.derivative.ca/ по визуальному програмированию всего совсем для роботов аудио визуальных интерактивных сэтапов а теперь есть html5 и blend4web)
Всех Благ
Роман
 
Пожалуйста, зарегистрируйтесь или войдите под своей учетной записью , чтобы оставлять сообщения.