Сериализация функций интерполяции
В многоязычном приложении компилирую переводы, содержащие логику, в ангуляровские выражения:
"{{{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); } } Можно как-нибудь подтянуть зависимости или сделать так, чтобы Ангуляр на клиенте смог выполнить такую функцию? |
Как ты себе сам представляешь "как-нибудь подтянуть зависимости"?
О каких зависимостях идет речь? Модули Angular'а или переменные? В Angular'е есть injecter, может тебе поможет angular.injector(['ng']).invoke(['$filter', function($f){ console.log($f('number')(1.2345, 2)); }]); |
Можно и с инжектором, но тогда огого-парсер придется писать. Оставим пока этот вариант. Допустим я все-же собрал работоспособную функцию, сериализовал. Как ее раскукожить на клиенте? new Function? eval?
Мои эксперименты показали, что для небольших выражений new Function в несколько раз медленнее чем парсинг их через $interpolate... |
То есть ты хочешь
server_on_node: "{{...}}" -> function -> string -> http_response client_in_browser: http_response -> string -> function -> выполнить функцию и получить результат Если так, то тебе не кажется, что отправить "{{...}}" быстрей и дешевле по ресурсам, чем трансформация "{{...}}" -> function -> string -> function -> function();? |
Кажется. Так и есть, на самом деле.
Поэтому сейчас вместо того, чтобы делать функцию из строки на клиенте планирую внедрить эту функцию непосредственно в js-файл приложения. Например, собрать грунтом отдельный ангуляровский модуль с константой и подключить его как зависимость. Но задача остается: функцию нужно как-то перевести в строку, чтобы грунтовский сборщик мог с ней работать. |
Как я вижу это процесс, собрать все переменные из текста функции, через eval() получить сами переменные, если будут функции делаем тоже самое.
|
Скорее это я вызвал путаницу :)
Сейчас используется вариант №1 (он, кстати, оказался не таким уж медленным. Обработка каждого выражения на клиенте занимает не больше 1 мс) Пробовал использовать вариант №2 (только функцию собирал в строку вручную), он оказался медленнее Теперь думаю про вариант №3 1. сервер через $interpolate делает функцию из строки str, 2. полученную функцию конвертирует в строку (тоже не прадставляю как это сделать), 3. собирает все функции в ангуляровский модуль и включает его в файл приложения, 4. клиент при загрузке проверяет, что есть модуль с функциями и использует их параметром $scope(или что-то другое) и получает текст, 5. который показывает пользователю. Это по-любому будет самый быстрый вариант, но сериализовать, полученную через $interpolate функцию, скорее всего не получится. Наверное, проще будет распарсить выражение и вручную превратить его в функцию... P.S. О ресурсах сервера можно не беспокоиться, т.к. это не бэкенд сервер, а машина разработчика. |
Прочитав немного Замыкания, функции изнутри и немного стандарта ECMA-262, тебе придется писать свой $interpolate, так как окружение функции хранится в С++, из JS его ни как не получить.
|
Потом, когда закончишь, можешь выложить результаты тестов на производительность?
|
Думаю, проще просто обернуть это выражение в функцию (ангуляровские выражения это просто урезанный js). только предварительно заменить все переменные с n на context.n (контекст приходит в качестве параметра) и вырезать опасные слова... Если займусь этим, обязательно выложу тесты
|
Часовой пояс GMT +3, время: 04:03. |