Динамичекий импорт пользовательских модулей
03 декабря 2014 05:36
Здравствуйте.
Поправьте меня, если я ошибаюсь.
На данный момент, если я хочу использовать написанный мною модуль, то я должен ручками тэгом script подключить его к странице, и после этого я уже могу его require(). Но допустим, у меня в приложении 50 таких модулей, в каждом по 5000 строк кода и каждый из которых усердно трудится. Соответственно, мой многострадальный браузер будет смиренно грузить все эти модули независимо от того, будут они использоваться далее или нет. Как следствие - ненужные обращения к серверу, лишний траффик. Для домашних рабочих станций с хорошим каналом это будет не так заметно, но вот на мобильных устройствах скорость оставляет желать лучшего.
Как вы смотрите на то, чтоб модуль загружался браузером всего один раз и только при первом require() этого модуля? Можно было бы ввести соглашение имен, как это сделано в nodejs - все пользовательские модули лежат в определенной директории, имя директории модуля должно совпадать с именем модуля, а исходный текст должен лежать например в module.js…
В принципе, это конечно можно оставить и на откуп разработчикам…. Я это реализовал вот так Код не претендует на эталон, но принцип понятен. Тут есть загвоздка с потоками. Если попытаться импортировать один и тот же модуль через небольшой интервал времени, то этот скрипт поведет себя непредсказуемо т.к. неизвестно, успеет ли загрузиться файл до второго вызова или нет. Должно решиться синхронизацией.
Простите, если несу ересь в массы
Поправьте меня, если я ошибаюсь.
На данный момент, если я хочу использовать написанный мною модуль, то я должен ручками тэгом 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. Так исчезнет проблема со временем загрузки, т.к. они будут грузиться асинхронно и не будут блокировать старт приложения, но всё равно останется ненужный трафик.
Думаю, стоит оставить реализацию на разработчика приложения, если ему действительно это понадобится.
В большинстве случаев размер кода не настолько большой, чтобы экономить на загрузке. У себя мы используем 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)
Всех Благ
Роман
Роман