Задать вопрос
  • Насколько актуально использование шаблонизаторов на сервере?

    bingo347
    @bingo347
    Crazy on performance...
    Есть такая весьма полезная, но иногда трудно реализуемая (зависит от выбранного стека) штука, как двухсторонний рендеринг. Преимущества в скорости выдачи готового к потреблению контента, как при первом запросе к сайту (серверный рендеринг), так и при последующих (клиентский рендеринг).
    Один из подходов упрощения реализации - вынос рендеринга в отдельный слой, способный работать, как на клиенте так и на сервере. Притом на сервере, скорее всего, он будет работать под node.js (так как на клиенте у нас только js), хотя и не обязательно (handlebars шаблоны легко реализуются на php или python).
    При этом слой api может быть реализован на любом языке.
    Пример: фронтенд (под ним я понимаю слой UI + UX) на vue, api на Go. Для серверного рендеринга нам нужна упрощенная реализация vue, без байндинга с DOM, но способная выдавать html в виде строки - VueSSR (не очень оптимизированая вещь, но нагрузка на серверный рендеринг как правило не большая).
    Есть еще два важных момента:
    Во-первых, крайне не желательно, чтоб на клиентской стороне не тратились и так дефицитные ресурсы на старте на рендеринг, который уже выполнен (vueRootVM.$mount()).
    Во-вторых, серверному рендерингу скорее всего понадобится доступ к api. Необходимо его упростить, чтобы запросы шли в обход nginx, напрямую, по локальной сети (в случае разных машин под api и рендеринг) или по unix сокету (в случае одной машины).

    Подводя итог. Актуально ли делать серверный рендеринг? Зависит от проекта. В любом случае, в современном мире он может существовать только в дополнение к клиентскому. А стоит ли оно того - решает каждый сам.
    Ответ написан
    1 комментарий
  • Стоит ли минифицировать и склеивать файлы, если есть http2 и gzip?

    bingo347
    @bingo347
    Crazy on performance...
    добавлю к вышесказанному про http/2:
    без "умных" server-push бандл содержащий весь код сайта для каждой страницы будет грузится быстрее отдельных модулей, даже если Вы грузите их далеко не все.
    просто представьте, вы грузите html -> он обрабатывается -> начинает грузить стили, картинки и главный модуль js -> js обрабатывается -> грузит еще 5 модулей, которые после обработки грузят еще 50 модулей
    а теперь просто подумайте - у Вас сотня файлов, которые грузятся параллельно в одном tcp потоке, к тому же обернутом в tls - что добавляет. оверхед на шифрование и дешифровку + добавим сюда оверхед на парсинг js, который будет задерживать сеть, а сеть его

    выхода из этого 2
    - или по прежнему отдавать все одним бандлом
    - или настраивать push, но с этим тоже траблы, ибо помимо вычисления файлов нужных начальному запросу (хоть и сложно, но вполне реально), нужно предсказывать, а что у браузера уже в кэше (ошибемся - получим или начальный оверхед (не отдали нужное) или сожрем лишний трафик (отдали ненужное))
    Ответ написан
    Комментировать
  • Как вывести заголовок перед каждым Div?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    id элемента должен быть уникальным на всю страницу, используйте class

    P.S. почему бы не сделать это через стили?
    Ответ написан
    Комментировать
  • Как проверить, завершилось ли действие, вызванное из другого компонента?

    bingo347
    @bingo347
    Crazy on performance...
    Во-первых, dispatch возвращает промис, притом если экшен возвращает промис, то dispatch вернет именно его
    То есть можем сделать примерно следующее:
    // экшн:
    InitChatSystem() {    
            return axios.get('/api/initChat')
                .then(res => {
                    this.commit('chat/initArticles', res.data.articles);                
                    this.commit('chat/initNotifications', res.data.notifications);               
                })
                .catch(err => {
                    console.log(err);                
                })
    },
    
    
    // хук:
    created() {
      this.$store.dispatch('chat/InitChatSystem').then(() => {
        // тут запускаем нашу мутацию
        // но как я понял, она в дочернем компоненте
        // нужно навесить ref на компонент, а в самом компоненте сделать метод запуска
        // а здесь будет что-то типа:
        this.$refs.child.run();
      });
    },


    Второй вариант, чисто на возможностях Vuex:
    // дождемся, когда в state.articles появятся данные
    activated() {            
      const unwatch = this.$store.watch(state => state.articles.length, length => {
        if(length === 0) { return; }
        unwatch();
        this.$store.commit('chat/openConversationArticle', this.article_id);
      });
    },
    Ответ написан
    Комментировать
  • Как сохранить в localStorage значения нескольких input[radio]?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Для начала хочу поругаться! Ибо наговнокодят, а потом "браузеры тормозят и жрут память"...
    1. Никогда не создавайте функции в циклах! НИКОГДА! Тем более однотипные.
    2. Никогда не создавайте объект (тем более такой тяжелый как массив), только ради того, что бы дернуть метод его прототипа!
    3. К ошибкам... Вы пробовали запускать свой код с пустым localStorage? Попробуйте...
    4. Еще к ошибкам... Что будет с Вашими данными, если придет простая таска: "Добавить еще один радио между первым и вторым"?
    5. Ну и не к производительности, а к читабельности и поддерживаемости:
    Вы сами то разбираетесь в этих Ваших переменных a, b, c, d, e?

    Теперь по теме:
    input[type=radio] - это переключатель. Среди нескольких радио с одинаковым name выбран может быть только один. Вам нужно хранить не индекс - checked (чем вообще череват индекс - смотрите п.4 в моей критике), а name - value выбранного радио

    Что ж, пожалуй поправлю, а заодно порефакторю Ваш код:
    (function(selector) {
        // не дублируем код
        function save(data) {
            localStorage.setItem(selector, JSON.stringify(data));
        }
        // и не создаем тысячи функций в цикле
        // а используем одну общую
        function onChange(event) {
            var element = event.target,
                name = element.name,
                value = element.value;
            data[name] = value;
            save(data);
        }
        var elements = document.querySelectorAll(selector),
            data = localStorage.getItem(selector);
        if(data) { // если в сторадже что-то есть
            // то можем и распарсить
            data = JSON.parse(data);
        } else {
            // иначе парсить нельзя, будет ошибка
            // присвоим дефолтное значение и сохраним
            save(data = {});
        }
        // вместо ненужного создания массива
        // обратимся напрямую к прототипу
        Array.prototype.forEach.call(elements, function(element) {
            var name = element.name,
                value = element.value;
            if(data[name] === value) { // если текущий элемент отмечен в сторадже
                // то отметим и на странице
                element.checked = true;
            }
            // навесим созданый вне цикла хандлер на событие
            element.addEventListener("change", onChange);        
        });
    })(/* ".stat_inp_r"
      А еще к селектору вопрос, мы только с этим классом радио будем запоминать?
      или же у нас каждый будет помнится?
      если каждый, то может имеет смысл обработать их все за раз:
    */ "input[type=radio]");
    Ответ написан
    2 комментария
  • Как вывести значение двумерного массива json?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Вы итерируете по полям response, а ключи подставляете в response['operation']
    нужно так:for(var i in response['operation']) {
    Ответ написан
    2 комментария
  • Как извлечь нужные данные из объектов JSON?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    Примерно так:
    const users = require('./users.json');
    for(const id of Object.getOwnPropertyNames(users)) {
      const {name, rank} = users[id];
      console.log(`Пользователь ${name} с рангом ${rank} имеет ID ${id}`);
    }
    Ответ написан
    Комментировать
  • Как отсортировать текст по дате?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Ответ написан
    Комментировать
  • SASS - LESS - Stylus что выбрать?

    bingo347
    @bingo347
    Crazy on performance...
    Вопрос конечно больше вкуса, но все же SASS в синтаксисе SCSS
    Из плюсов могу сказать:
    - Самый богатый функционал (ИМХО)
    - CSS - это валидный SCSS
    - Многие библиотеки написаны сегодня на нем, что позволяет подгружать их по частям или использовать на уровне миксинов и функций
    - Возможность переопределить загрузку import'ов
    - Возможность писать функции на языке сборки - в большинстве случаев не надо, но все же полезно
    - Единое ядро на C и байндинги ко множеству языков
    Ответ написан
    4 комментария
  • Можно ли с помощью Service Worker перехватить и изменить http запрос?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Одна из задач Service Worker - именно программируемый прокси на стороне клиента.
    То есть на Ваш вопрос "можно?" - я бы ответил, да - это одна из основных функций Service Worker.
    Но есть одно но, Service Worker работает только с тем доменном, с которого загружен его код. То есть можно перехватывать только запросы к своему домену. Притом, данная функция доступна только для не кросдоменных запросов (тех что идут со страниц своего же домена). Стоит так же упомянуть экспериментальное событие foreignfetch упомянутое в сводке фич chrome на google developers за сентябрь "16 - оно позволяет перехватывать обращение к своему домену с чужих ресурсов, но о нем не знает ни mdn, ни caniuse - как следствие событие потенциально работает только в chrome 54+.
    Так же стоит учитывать, что поддержка Service Worker хорошо реализована только в Chrome и Firefox. В Edge появилась с 17 версии (вышедшей вместе с win10 April"18 update), в safari тоже появилась недавно (11.1 - десктоп, 11.4 - iOS)

    Если это все устраивает, то:
    Читаем эту статью на mdn: https://developer.mozilla.org/ru/docs/Web/API/Serv...
    Так как из стать выше для Вашей задачи можно почерпнуть только работу с событием fetch (с событием foreignfetch работаем аналогично) и большинство примеров нацелены на программируемый кэш, а для подделки запросов нужно генерировать свой объект Responce - читаем эту статью: https://developer.mozilla.org/en-US/docs/Web/API/R... (only English)
    Так же читаем про Request: https://developer.mozilla.org/en-US/docs/Web/API/R...

    Вся суть будет сводится примерно к следующему коду Service Worker:
    self.addEventListener('fetch', event => {
      const {request} = event;
      // обрабатываем request чтоб понять, что от нас хотят
      //...
      if(/* условие, что запрос нужно подменить */) {
        event.respondWith(new Response('Hello world', /* вместо строки можно Blob или ArrayBuffer */ {
          headers: { 'Content-Type': 'text/plain' }
        }));
      } else {
        event.respondWith(fetch(request)); // если не наш случай, отправляем запрос на сервер,
        // тут так же можно заморочится с кэшем
      }
    });


    Если же какие то условия не подходят, то единственным выходом будет навязывать юзеру наше расширение для браузера... благо с последней политикой партии втихаря их уже не поставить.
    Ответ написан
    Комментировать
  • Почему не работает код, Vue.js?

    bingo347
    @bingo347
    Crazy on performance...
    Мне кажется нужно сначала разобраться в JS
    Рассмотрим Ваш метод построчно:
    fontFamily: font,
    // создали метку  fontFamily, которая здесь бесполезна,
    // далее бесполезное обращение к переменной,
    // далее оператор запятая
    currentFont = font,
    // тут вроде бы должны присвоить значение font в currentFont
    // так как currentFont нигде не объявлено - будет ошибка
    // ну и опять оператор запятая, а значит не фига в currentFont не будет font
    FPisActive = false
    // а будет там результат вот этого выражения, то есть false
    // опять же FPisActive не объявлено - ошибка


    Повангую, и предположу, что Вы хотите поменять данные, тогда нужно так:
    pickFont: function (font) {
          this.signStyle.fontFamily = font;
          this.currentFont = font;
          this.FPisActive = false;
    }
    Ответ написан
    5 комментариев
  • Как подключить стили VueMaterial, к webpack?

    bingo347
    @bingo347
    Crazy on performance...
    {
                    test: /\.(sa|sc|c)ss$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'sass-loader',
                    ],
                },
                {
                    test: /\.css$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        "css-loader"
                    ]
                }

    У Вас для css правила продублированы:
    test: /\.css$/ - отработает на всех файлах оканчивающихся на .css
    test: /\.(sa|sc|c)ss$/ - отработает на всех файлах оканчивающихся на .sass или .scss или .css

    sass-loader - ожидает на вход sass/scss, выдает css
    css-loader ожидает на вход css а выдает js
    MiniCssExtractPlugin.loader ожидает на вход js подобный выдаче css-loader и отдает js (+ добавляет child - css bundle)

    В Вашем же конфиге получается, что на вход sass-loader приходит js сгенерированный MiniCssExtractPlugin.loader

    Должно помочь:
    test: /\.(sa|sc|c)ss$/ заменяем на test: /\.(sa|sc)ss$/
    дабы .css файлы обрабатывались только своим правилом

    UPD: лучше подключать стили vue-material через sass, как это описано здесь:
    https://vuematerial.io/themes/configuration
    ибо скорее-всего Вам понадобится кастомизация темы
    Ответ написан
  • Существует ли готовое решение для создания 3D изображения из серии фотографий?

    bingo347
    @bingo347
    Crazy on performance...
    Сразу оговорюсь, многое зависит от фотографий, их качества, фона за объектом (особенно если нужно его вырезать), дрожания камеры при съемке (лучше снимать с подвижного штатива на круговых рельсах)

    Большую часть работы займет подготовка текстуры, которую нужно создать из серии фото. Думаю лучше всего для этого подойдет инструмент Photomerge из Photoshop
    Почитать можно тут: https://helpx.adobe.com/ru/photoshop/using/create-...

    Дальше будем рисовать на webGL (для простоты можно использовать библиотеку THREE.js)
    Создаем на сцене цилиндр (если вращаем только в 1 плоскости) или сферу (в 3 плоскостях) и натягиваем на него нашу текстуру. Стоит заметить, что для цилиндра и сферы нужны немного разные текстуры, Photomerge умеет делать и те и те.
    Помещаем нашу фигуру на сцене так, чтоб центр сцены совпал с центром фигуры. То есть в точке (0, 0, 0).
    Далее нам понадобится перспективная камера, создаем, размещаем ее на некотором удалении от центра и направляем на центр.
    При вращении фигуры оперируем чисто положением камеры. Вращаем ее вокруг объекта так, что бы расстояние до центра не менялось (в случае цилиндра это чуть проще, так как координата Z не меняется, но в любом случае, знания геометрии пригодятся). При каждом перемещении не забываем снова направлять камеру на центр фигуры.
    Ответ написан
  • У примитивных значений тоже есть методы?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    По поводу объектных оберток MaxKorz уже дал хороший ответ, поэтому отвечу лишь на вторую часть, насчет оператора +=
    Данный оператор является по сути оператором присваивания, а у оператором присваивания левым операндом может быть только переменная, в Вашем же примере слева выражение text.slice(0,5)
    Ответ написан
    Комментировать
  • Можно ли во Vue.js создавать несколько родительских компонентов?

    bingo347
    @bingo347
    Crazy on performance...
    Во-первых посмотрите в сторону vue-router
    В его же документации можно найти про динамический импорт
    Кроме того, вряд ли точка входа - app.vue, скорее это некий .js файл, который импортит app.vue, это если ручками захочется этим всем рулить.
    Ну и наконец, тот же webpack позволяет Вам иметь несколько точек входа и даже для каждой свой конфиг задать
    Ответ написан
    3 комментария
  • Как хранить краткосрочные данные?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    редис / тарантул / аэроспайк / другое хранилище в памяти подходящее под задачу
    проблема с хранением в памяти процесса - такое решение не маштабируемо, стоит запустить 2й процесс ноды, и все, у Вас будет рассинхрон данных
    Ответ написан
    Комментировать
  • Рекурсивное каррирование?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Вся проблема в том, что Вы на каждый вызов переопределяете метод valueOf у оригинальной функции, правильнее возвращать каждый раз новую функцию:
    const curring = (...initArgs) => {
      let sum = 0;
      const curried = (...args) => {
        sum = args.reduce((a, b) => a + b, sum);
        return curried;
      };
      curried.valueOf = () => sum;
      return curried(...initArgs);
    };
    Ответ написан
    Комментировать
  • Воспроизведение аудио?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Полностью обойти не получится, ибо политика против агрессивного воспроизведения звука.
    Звук, что у video что у audio, можно включать только синхронно по действию пользователя.
    В blink (chrome, chromium, etc.) прокатит хак, если на действие пользователя вызвать метод load(), после play() можно вызывать когда угодно. Однако хак не работает в AppleWebkit (Safari на osX, любой браузер на iOS).

    Кроме того, эту ситуацию можно отлавливать. В современных браузерах метод play возвращает промис, который резолвится после удачного запуска и реджектится при неудачном (как в Вашем примере).
    Ответ написан
    3 комментария
  • Почему этот цикл намертво вешает вкладку?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Array.prototype.forEach.call(document.querySelectorAll('.post *'), function(e) {
      for(var i = e.attributes.length; i--;) {
        if(e.attributes[i].nodeName !== 'href') {
          e.removeAttributeNode(e.attributes[i]);
        }
      }
    });
    Ответ написан