Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 27.04.2014, 23:10
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Сериализация функций интерполяции
В многоязычном приложении компилирую переводы, содержащие логику, в ангуляровские выражения:
"{{{0:1,8:1}[n]==1 ? {0:'%нет тарелок '+{'0':'добави’ло = 5', '1':'добавил', '2':'добавила'}[s]+'',8:'тарелочки!'}[n] : {one:''+n+' тарелка',few:''+n+' ’тарелки',many:''+n+' ″тарелок″',other:''+n+' сколько-то тарелок'}[n%1==0 ? (n%10==1 && n%100!=11 ? 'one' : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 'few' : 'many') : 'other']}}

Далее Ангуляр читает JSON со строками, парсит и выполняет.

Хочу парсить заранее и в JSON класть сериализованные функции, для чего поставил Ангуляр на node.js и обрабатываю строки методом $interpolate.

Проблема в том, что сериализация полученной функции методом toString() выдает такое:
function (context) {
          try {
            for(var i = 0, ii = length, part; i<ii; i++) {
              if (typeof (part = parts[i]) == 'function') {
                part = part(context);
                if (trustedContext) {
                  part = $sce.getTrusted(trustedContext, part);
                } else {
                  part = $sce.valueOf(part);
                }
                if (part === null || isUndefined(part)) {
                  part = '';
                } else if (typeof part != 'string') {
                  part = toJson(part);
                }
              }
              concat[i] = part;
            }
            return concat.join('');
          }
          catch(err) {
            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
                err.toString());
            $exceptionHandler(newErr);
          }
        }

Можно как-нибудь подтянуть зависимости или сделать так, чтобы Ангуляр на клиенте смог выполнить такую функцию?

Последний раз редактировалось Shitbox2, 27.04.2014 в 23:13.
Ответить с цитированием
  #2 (permalink)  
Старый 28.04.2014, 10:36
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

Как ты себе сам представляешь "как-нибудь подтянуть зависимости"?
О каких зависимостях идет речь? Модули Angular'а или переменные?

В Angular'е есть injecter, может тебе поможет
angular.injector(['ng']).invoke(['$filter', function($f){
     console.log($f('number')(1.2345, 2));
}]);
Ответить с цитированием
  #3 (permalink)  
Старый 28.04.2014, 11:05
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Можно и с инжектором, но тогда огого-парсер придется писать. Оставим пока этот вариант. Допустим я все-же собрал работоспособную функцию, сериализовал. Как ее раскукожить на клиенте? new Function? eval?

Мои эксперименты показали, что для небольших выражений new Function в несколько раз медленнее чем парсинг их через $interpolate...
Ответить с цитированием
  #4 (permalink)  
Старый 28.04.2014, 13:49
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

То есть ты хочешь
server_on_node: "{{...}}" -> function -> string -> http_response
client_in_browser: http_response -> string -> function -> выполнить функцию и получить результат
Если так, то тебе не кажется, что отправить "{{...}}" быстрей и дешевле по ресурсам, чем трансформация "{{...}}" -> function -> string -> function -> function();?
Ответить с цитированием
  #5 (permalink)  
Старый 28.04.2014, 21:23
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Кажется. Так и есть, на самом деле.

Поэтому сейчас вместо того, чтобы делать функцию из строки на клиенте планирую внедрить эту функцию непосредственно в js-файл приложения. Например, собрать грунтом отдельный ангуляровский модуль с константой и подключить его как зависимость. Но задача остается: функцию нужно как-то перевести в строку, чтобы грунтовский сборщик мог с ней работать.
Ответить с цитированием
  #6 (permalink)  
Старый 29.04.2014, 07:38
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

Как я вижу это процесс, собрать все переменные из текста функции, через eval() получить сами переменные, если будут функции делаем тоже самое.

Последний раз редактировалось FireVolkhov, 29.04.2014 в 09:11.
Ответить с цитированием
  #7 (permalink)  
Старый 29.04.2014, 08:12
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Скорее это я вызвал путаницу

Сейчас используется вариант №1 (он, кстати, оказался не таким уж медленным. Обработка каждого выражения на клиенте занимает не больше 1 мс)

Пробовал использовать вариант №2 (только функцию собирал в строку вручную), он оказался медленнее

Теперь думаю про вариант №3
1. сервер через $interpolate делает функцию из строки str,
2. полученную функцию конвертирует в строку (тоже не прадставляю как это сделать),
3. собирает все функции в ангуляровский модуль и включает его в файл приложения,
4. клиент при загрузке проверяет, что есть модуль с функциями и использует их параметром $scope(или что-то другое) и получает текст,
5. который показывает пользователю.

Это по-любому будет самый быстрый вариант, но сериализовать, полученную через $interpolate функцию, скорее всего не получится. Наверное, проще будет распарсить выражение и вручную превратить его в функцию...

P.S. О ресурсах сервера можно не беспокоиться, т.к. это не бэкенд сервер, а машина разработчика.

Последний раз редактировалось Shitbox2, 29.04.2014 в 08:15.
Ответить с цитированием
  #8 (permalink)  
Старый 29.04.2014, 09:10
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

Прочитав немного Замыкания, функции изнутри и немного стандарта ECMA-262, тебе придется писать свой $interpolate, так как окружение функции хранится в С++, из JS его ни как не получить.
Ответить с цитированием
  #9 (permalink)  
Старый 29.04.2014, 09:15
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

Потом, когда закончишь, можешь выложить результаты тестов на производительность?
Ответить с цитированием
  #10 (permalink)  
Старый 30.04.2014, 00:45
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Думаю, проще просто обернуть это выражение в функцию (ангуляровские выражения это просто урезанный js). только предварительно заменить все переменные с n на context.n (контекст приходит в качестве параметра) и вырезать опасные слова... Если займусь этим, обязательно выложу тесты
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Потоки данных и параллельное выполнение функций Dorian_bs Общие вопросы Javascript 11 10.01.2014 18:58
Много js функций получается Evgeny_Dedov jQuery 4 15.07.2013 15:17
Непонятный алгоритм отработки функций Jopses jQuery 5 16.02.2013 12:55
Применение анонимных функций Бормртун Общие вопросы Javascript 10 29.12.2011 12:41
Как получить список пользовательских функций объекта window? Маэстро Events/DOM/Window 13 03.07.2010 13:20