Задать вопрос
  • Как слушать несколько портов и адресов в http.js?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    Придется поднять 2 инстанса http сервера, каждый на своем порту и адресе.
    В принципе их можно будет использовать с общим app, так как и у req и у res есть свойство socket, являющееся инстансом net.Socket, а значит из него можно получить адрес и порт:
    https://nodejs.org/dist/latest-v14.x/docs/api/http...
    https://nodejs.org/dist/latest-v14.x/docs/api/http...
    https://nodejs.org/dist/latest-v14.x/docs/api/net....
    var app = require('express')();
    var http = require('http');
    var server1 = http.createServer(app);
    var server2 = http.createServer(app);
    
    server1.listen(PORT1, ADDRESS1);
    server2.listen(PORT2, ADDRESS2);

    io правда придется создать 2 инстанса, но обработчики событий опять же можно навесить общие.
    Ответ написан
    Комментировать
  • Когда надо пушить git push --tags?

    bingo347
    @bingo347
    Crazy on performance...
    git push просто без параметров зальет все локальные коммиты в последнюю удаленную ветку, если git знает о том, какая последняя конечно
    git push с флагом -u позволяет указать, какой именно удаленный репозиторий (в вопросе это origin) и в какую в нем ветку (в вопросе это master) заливать коммиты
    git remote управляет удаленными репозиториями
    в частности git remote add добавляет новый под указанным именем (в вопросе это origin) и находящийся под указанным url (в вопросе это https://github.com/.git)
    git push --tagsзаливает в последнюю удаленную ветку только тэги, без коммитов
    но тэг - это всего лишь символьная ссылка на конкретный коммит и без самого коммита смысла в ней нет
    поэтому git push --tags должно идти после git push
    Ответ написан
    2 комментария
  • Узнать данные из библиотеки .so?

    bingo347
    @bingo347
    Crazy on performance...
    Ответ написан
    Комментировать
  • Как изолировать или обнулить встраиваемое приложение от внешних стилей?

    bingo347
    @bingo347
    Crazy on performance...
    Встраиваемое приложение должно быть в iframe, только так на сегодня можно 100% изолировать и стили и скрипты.
    Элементарно будет на сайте банальное
    div {
      color: red !important;
    }
    и Ваше приложение уже будет выглядеть не так.
    Ну а еще встречается js с манкипатчингом.
    А iframe вполне хорошо Вас защитит и от того и от другого
    Ответ написан
    2 комментария
  • Как выбросить ошибку из промиса?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Ваша главная проблема в говнокоде, в котором Вы сами не в состоянии разобраться.

    Для начала я отрефакторю вот этот кусок:
    const minSalary = Math.min(...employeeData.map(({ salary }) => salary));
    minSalaryEmployee = employeeData.filter(({ salary }) => {
        return salary === minSalary;
    });
    const [id, oldSalary] = [
        minSalaryEmployee[0].id,
        minSalaryEmployee[0].salary,
    ];
    const newSalary = oldSalary + (oldSalary / 100) * 20;
    return { id: id, salary: newSalary };
    ибо тут твориться полная жесть...
    Если привести в более читабельный вид:
    const minSalary = Math.min(...employeeData.map(({salary}) => salary));
    const minSalaryEmployee = employeeData.find(({salary}) => salary === minSalary);
    const {id, salary: oldSalary} = minSalaryEmployee;
    const newSalary = oldSalary + (oldSalary / 100) * 20;
    return {id, salary: newSalary};
    то сразу можно увидеть простор для оптимизации поиска минимума:
    const [minSalaryEmployee] = employeeData.reduce(([minEmployee, minSalary], employee) => {
        const {salary} = employee;
        return (salary < minSalary
            ? [employee, salary]
            : [minEmployee, minSalary]
        );
    }, [null, Infinity]);
    А заодно и формулу
    const newSalary = oldSalary + (oldSalary / 100) * 20;
    применив алгебру за 5 класс можно упростить доconst newSalary = oldSalary * 1.2;

    Следующим шагом стоит развернуть все промисы. Вообще вкладывать промисы в друг друга не очень хорошая идея. Наличие .then внутри колбэка другого .then или колбэка-раннера new Promise - воняет очень скверно.

    Немного поколдовав, заодно исправив ошибки с колбэками .then без return, получаем более читабельный, а главное работающий код:
    function increaseSalary() {
        return api.getEmployees()
            .then(employeeData => {
                const [minSalaryEmployee] = employeeData.reduce(([minEmployee, minSalary], employee) => {
                    const {salary} = employee;
                    return (salary < minSalary
                        ? [employee, salary]
                        : [minEmployee, minSalary]
                    );
                }, [null, Infinity]);
                const {id, salary: oldSalary} = minSalaryEmployee;
                const newSalary = oldSalary * 1.2;
                return {id, salary: newSalary};
            })
            .then(({id, salary}) => api.setEmployeeSalary(id, salary))
            .then(({name, id, salary}) => api.notifyEmployee(id, `Hello, ${name}! Congratulations, your new salary is ${salary}!`))
            .catch(e => api.notifyAdmin(e));
    }


    P.S. я бы еще бил все это добро на отдельные функции, ибо complexity 10 это все еще много...

    import api from 'path/to/api';
    
    export function increaseSalary() {
        return api.getEmployees()
            .then(findEmployeeWithMinSalary)
            .then(calculateNewSalary)
            .then(setEmployeeSalary)
            .then(notifyEmployee)
            .catch(notifyAdmin);
    }
    
    function findEmployeeWithMinSalary(employeeData) {
        const [minSalaryEmployee] = employeeData.reduce(minSalaryEmployeeReducer, [null, Infinity]);
        return minSalaryEmployee;
    }
    
    // Complexity is 3 - это самая сложная функция
    function minSalaryEmployeeReducer([minEmployee, minSalary], employee) {
        const {salary} = employee;
        return (salary < minSalary
            ? [employee, salary]
            : [minEmployee, minSalary]
        );
    }
    
    function calculateNewSalary({id, salary}) {
        return {
            id,
            salary: salary * 1.2
        };
    }
    
    function setEmployeeSalary({id, salary}) {
        return api.setEmployeeSalary(id, salary);
    }
    
    function notifyEmployee({name, id, salary}) {
        return api.notifyEmployee(id, `Hello, ${name}! Congratulations, your new salary is ${salary}!`);
    }
    
    function notifyAdmin(e) {
        return api.notifyAdmin(e);
    }
    Ответ написан
    1 комментарий
  • Добавлять/убирать класс у элементов при скролле?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Вопрос поднимался здесь уже много раз...

    1. Оптимизировать можно с помощью IntersectionObserver
    2. Просто убирайте класс со всех остальных элементов
    Ответ написан
    Комментировать
  • Как обернуть данные из колбэков в массив?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Решение 0xD34F имеет сложность O(n2) из-за использования метода every
    Если это тестовое задание, могут и придраться, так как обычный счетчик позволяет решить со сложностью O(n)
    function getUsersInfo(ids, callback) {
      const {length} = ids;
      const results = Array(length);
      let doneCount = 0;
      ids.forEach((id, i) => {
        getUserInfo(id, user => {
          results[i] = user;
          doneCount++;
          if(doneCount === length) {
            callback(result);
          }
        });
      });
    }

    Ну и замечу, что Promise.all в v8 под капотом использует именно такой подход (разве что подсчет ведут от length к 0):
    https://github.com/v8/v8/blob/master/src/builtins/...
    Ответ написан
    1 комментарий
  • Как сделать option якорной ссылкой?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Ответ написан
    Комментировать
  • Каким путем лучше пойти при хранении индентефекатора сессии?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    Самый безопасный способ - кука с флагами secure и http-only, с ней может работать только сервер и передается она только по https.
    Все остальное спокойно уводится любым сторонним скриптом на Вашем сайте
    Ответ написан
    Комментировать
  • Одно ли и то же эти куски кода?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    1 - function expression
    Функция будет анонимная (без имени), что затруднит отладку, а так же не позволит делать рекурсивные вызовы.
    var всплывет наверх функции в которой была объявлена (оборачивающей), но до присваивания будет иметь значение undefined, вызов приведет к ошибке.
    Данный тип функций вообще не должен использоваться в нормальном коде.
    Функцию можно переопределить в последствии

    2 - named function expression
    Похоже на предыдущее, но имеет имя, что упрощает отладку и позволяет делать рекурсивные вызовы. В остальном все тоже самое.
    Вот так в переменную опять же присваивать не стоит, для дебага хватит стрелочной функции присвоенной в константу (в дебаггере примет имя константы). Но рационально использовать для колбэков, где нужна рекурсия или опять же для удобного дебага.

    3. function declaration
    Всегда должна иметь имя. Всплывает на верх (можно вызывать до объявления). Нельзя переопределить внутри той же функции (всегда будет вариант, тот что объявлен ниже).

    Добавлю еще 4 - arrow function expressionconst func = () => {};на сегодня лучше использовать его вместо function expression
    Ответ написан
    3 комментария
  • Как при рекурсивном переборе древовидных объектов вызывать fetch на каждый item и на выходе получать измененный массив?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    const addingOptions = arr => Promise.all(arr.map(
        item => Promise.all([
            fetchOptions(item.id),
            item.children.length ? addingOptions(item.children) : []
        ]).then(([options, children]) => ({
            ...item,
            options,
            children
        }))
    ));
    Ответ написан
    Комментировать
  • Как предлагать пользователям рандомный вопрос?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Комментировать
  • Аналог electron только на GO?

    bingo347
    @bingo347
    Crazy on performance...
    Electron построен поверх CEF внедренного в ноду как нативный аддон.
    В рендер процессе нода подключается через libnode
    Все это вполне общается через сишный abi с которым умеет работать cgo.
    Ответ написан
    Комментировать
  • Как реализовать такое?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Для начала наш бэк должен уметь отвечать на запрос вида "дай мне N товаров после товара X", иначе такая кнопка в принципе не имеет смысл.
    Так вот, при нажатии на кнопку "Показать больше" мы первым делом должны ее заблокировать (чтоб пользователь не на тыкал лишнего) и показать лоадер (вдруг инет пользователя медленный), а затем отправить наш запрос к бэку, чтоб он дал нам данные о дополнительных товарах.
    Когда данные загрузились, отрисовываем их в конец и в зависимости от того, есть ли у бэка еще товары (это он тоже должен нам сказать) мы или разблокируем или прячем кнопку "Показать больше".
    Все.
    Ответ написан
    Комментировать
  • Какой язык поможет научиться грамотно подходить разработке на БЭ?

    bingo347
    @bingo347
    Crazy on performance...
    Хотите, чтоб компилятор бил по рукам за почти любые грехи - попробуйте Rust, хорошие практики он Вам точно привьет, а там глядишь, пока изучаете эти самые практики, и вакансий на нем больше будет.
    Но в любом случае, после Rust и на TS начинаешь писать иначе, лучше.
    Ответ написан
    Комментировать
  • Как найти и заменить значение вложенного объекта?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    function cloneWithReplace(
        // клонируемый объект
        obj,
        // объект с функциями вида value => newValue, в соответствующих ключах для замены
        // нужен не всегда, поэтому по умолчанию сделаем пустой объект
        replacers = {},
        // Map с значениями, которые уже склонировали, дабы не попасть в рекурсию
        // так как внешний код обычно его не будет передавать, зададим значение по умолчанию
        storeMap = new Map()
    ) {
        // для начала чекнем, что объект уже клонировали:
        if(storeMap.has(obj)) {
            return storeMap.get(obj);
        }
    
        // получим тип объекта, он нам пригодится пару раз, дабы отличать функции
        const type = typeof obj;
    
        // если obj примитив, то его можно просто вернуть
        if(obj === null || (type !== 'object' && type !== 'function')) {
            return obj;
        }
    
        // создадим переменную с результатом и инициируем ее в зависимости от типа оригинала
        let result;
        if(type === 'function') {
            // функцию можно "склонировать" лишь обернув
            result = function() {
                return obj.apply(this, arguments);
            };
            // неплохо бы, чтоб клон правильно сообщал имя функции и количество аргументов
            // но так как IE не ест такую магию, обернем в try-catch
            try {
                Object.defineProperties(result, {
                    name: Object.getOwnPropertyDescriptor(obj, 'name'),
                    length: Object.getOwnPropertyDescriptor(obj, 'length')
                });
            } catch {}
        } else if(Array.isArray(obj)) {
            // массивы клонируем рекурсивно, при помощи map
            result = obj.map(value => cloneWithReplace(value, replacers, storeMap));
            // так как нормальные массивы не содержат других полей, кроме числовых
            // можно сохранить клон в защиту от рекурсии и вернуть результат
            storeMap.set(obj, result);
            return result;
        } else {
            // для всех других объектов просто создадим новый объект и скопируем ему ссылку на прототип
            result = Object.setPrototypeOf({}, Object.getPrototypeOf(obj));
        }
    
        // сохраним клон в защиту от рекурсии
        storeMap.set(obj, result);
    
        // осталось склонировать поля с заменой тех случаев, где у нас есть replacer
        for(const key of Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))) {
            if(typeof replacers[key] === 'function') {
                // если есть replacer используем его
                result[key] = replacers[key](obj[key]);
            } else {
                // иначе клонируем поле рекурсивно
                result[key] = cloneWithReplace(obj[key], replacers, storeMap);
            }
        }
    
        return result;
    }
    
    // используем так:
    const newData = cloneWithReplace(data, {
        value: () => 'new value'
    });
    Ответ написан
    1 комментарий
  • Github: Один локальный репозиторий на два удаленных?

    bingo347
    @bingo347
    Crazy on performance...
    https://git-scm.com/book/ru/v2/Инструменты-Git-Под...
    сделать папку build подмодулем, у которого remote будет публичный репо
    Ответ написан
    Комментировать
  • Как изменить текст в буфере перед вставкой?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    document.addEventListener('paste', pasteText);
    function pasteText(e) {
      e.preventDefault();
      var txt = (e.originalEvent || e).clipboardData.getData('text/plain');
      e.target.value = txt;
    };
    Ответ написан
    1 комментарий
  • Есть программа для создания таблиц с программным кодом?

    bingo347
    @bingo347
    Crazy on performance...
    В экселе в ячейку можно вставить функции, в том числе написанные собственноручно на VBA
    В OpenOffice/LibreOffice Calc помимо VBA так же доступны Lua и JS
    В Google Sheets то же самое можно сделать на JS
    Ответ написан