Как стать автором
Обновить
34
0
Александр Кривощёков @SuperPaintman

Lead Software Engineer / Backend / Go / C++

Отправить сообщение

Григорий, хотел бы я написать вам "С подключением", не знай я про вас и ваши отличные доклады на конференциях. Но зачем мусолить эту тему по ES20xx, ведь уже есть тысячи однотипных статей про новый (уже не самый новый) стандарт?

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

Вероятнее всего, для вас это непонятно потому-что вы, возможно, не знакомы с async / await API и промисами в JS. Если произойдет ошибка в асинхронной функции, она свалится в ближайший .catch() или в unhandledRejection


Собственно сниппет


(async function () {
})()
  .catch((err) => {
    console.error(err);

    process.exit(1);
  });

достаточно распространен, и, если вы с ним хотя бы раз встречались, вам будет ясно куда скроллить.


try { } catch (err) { } конструкция гораздо более громоздка, голословна, и при этом менее ясна, чем if err := thingB(); err != nil {… }. 5 строк против 3, при нулевых бенефитах в данном случае, и еще и спрятанной магией передачи ошибки.

А если я не хочу вообще перехватывать эту ошибку, и другие на каждый чих, если я за fail-fast?


снова же, приходится бегать глазами от начала main до конца, чтобы понять, точно ли не упустил ничего из этого flow-а программы, раскиданным в нескольких местах.

См. пункт про сниппет. Вам не надо бегать глазами по main, в конце лишь выводится ошибка и завершается процесс, т.к. асинхронные функции не выбрасывают uncaughtException и не завершают процесс самостоятельно, если их не перехватить вручную.

Вы не правильно поняли мой посыл. Я не агитирую ни за Node, ни за Go. Я говорил, что есть вещи куда важнее, чем мериться бенчмарками и бесконечно переписывать с языка на язык (не забывайте, что скоро Rust станет меинстримом, и как заживем, как начнем рефакторить-переписывать :)).

Если подытожить все сказанное выше, пишите на чем вам удобнее и привычнее. Не там много задач, где узким местом будет именно выбранные язык, а не сеть и взаимодействие с диском. А если уж вы и упретесь в один из таких случаев, то нет смысла переписывать всю систему на "+5% к производительности" языке, а лучше задуматься о низкоуровневой реализации этого "горлышка" или же нативном аддоне.

Ну все, пойду переписывать все свои Node.js бэки на Go. А если серьезно, как-же достала это выдуманная проблема с языками и платформами (особенное с очень близкими по производительности). Т.е. выбор языка по бенчмаркам куда предпочтительнее, чем скорость разработки функционала / экосистема / синтаксис / высокоуровневость?


сделай вот эту штуку А, подожди ответ, может быть упади с ошибкой. Потом сделай штуку Б, подожди ответ, проверь ошибку. И в Node это намного сложнее, потому что ты должен для этого прыгать в вызов другой функции.

async function thingA() {
  // magic
}

async function thingB() {
  // magic
}

(async function main() {
  await thingA(); // И подождет ошибку, и сам упадет

  try {
    await thingB(); // Сделает штуку Б
  } catch (err) {
    // Проверит ошибку
  }
})()
  .catch((err) => {
    console.error(err);

    process.exit(1);
  });

Действительно, это гораздо сложнее и меннее читаемо чем постоянные if err != nil.


«зеленые потоки»

Event-loop не сравляется? Ок, fibjs, node-fibers, они должны быть чуть побыстрее. (нам ведь это реально нужно).


Но если вы пишете распределённый DNS сервер, я бы не выбирал Node.

А я бы выбрал C, нам ведь важны только бенчмарки, да?

Исторически мы привыкли, что блоки try catch проседают по перфомансу. Поэтому многие их избегают.

Это утверждение верно только для v8 ниже 5.8 (январь 2017, если не изменяет память) / Node.js v8.x.x. Да, конечно, не у всех еще обновлен хром / node до этих версий, тем не менее проблема решена, и ее доля в будущем будет только уменьшаться.


Ну и да, так как Reflect API появился достаточно недавно, придется использовать поллифил, а там try / catch.


Benchmarks

image


Ну и отлов ошибок через try catch более громоздкий

Зато он понятнее в разы, предположим, что я определяю в дескрипторе сразу несколько свойств, и происходит ошибка (TypeError: Cannot define property xxx, object is not extensible), в случае ошибки, можно понять, что именно произошло, а вот false мне мало о чем скажет.

Я понимаю, что сказанное ниже это вкусовщина (просто устал это видель в open-source проектах), но вы действительно считаете, что это:


const emptyObj = () =>
 new Proxy({},
   {
     get: (target, key, receiver) => (
        key == 'toJSON'
          ? () => target
          : (
              Reflect.has(target, key) ||
              Reflect.set(target, key, emptyObj()),
              Reflect.get(target, key, receiver)
            )
     )
   }
 )
;

понятнее, чем это:


const emptyObj = () => (
  new Proxy({}, {
    get(target, key, receiver) {
      if (key === 'toJSON') {
        return () => target;
      }

      if (!Reflect.has(target, key)) {
        Reflect.set(target, key, emptyObj());
      }

      return Reflect.get(target, key, receiver);
    }
  })
);

У вас 15 строчек, и у меня 15 строчек, но ИМХО, в if'ах нет ничено плохого, используйте логические операторы по их назначению.


Визуально отделить эту запятую весьма непросто:


Reflect.has(target, key) ||
Reflect.set(target, key, emptyObj()), // <==
Reflect.get(target, key, receiver)

p.s. конечно же не err.sendStatuc(500);, а res.sendStatus(500);. К сожалению, кончилось время редактирования, и пишу комментарием.

Зачем ради одной проверки на null копировать все поля? Не лучше ли было бы
сделать так:


// API
router.get('/words', async (req, res) => {
  const {userId} = req.query;
  const wordsSnapshot = await db.ref(`words/${userId}`).once('value');

  // Еще лучше
  const response = snapshot.val() || {};
  res.send(response);
});

Касаемо асинхронных функций в Express роутере, попробуйте сделать так (я не
думаю, что вы дождетесь ответа. Даже от обработчика ошибок):


router.get('/words', async (req, res) => {
  noSuchMethod(); // <=

  res.send({});
});

router.use((err, req, res, next) => {
  console.error(err);

  err.sendStatuc(500);
});

А исправить это можно вполне легко:


function isPromise(obj) {
  if (!obj || !obj.constructor) {
    return false;
  }

  if (obj.constructor.name === 'Promise'
    || obj.constructor.displayName === 'Promise') {
    return true;
  }

  return (typeof obj.then === 'function' || typeof obj.catch === 'function');
}

function wrap(fn) {
  const { length } = fn;

  if (length < 4) {
    return (req, res, next) => {
      const result = fn(req, res, next);

      return isPromise(result) ? result.catch(next) : result;
    };
  } else {
    return (err, req, res, next) => {
      const result = fn(err, req, res, next);

      return isPromise(result) ? result.catch(next) : result;
    };
  }
};

router.get('/words', wrap(async (req, res) => {
  noSuchMethod(); // <=

  res.send({});
}));

router.use((err, req, res, next) => {
  console.error(err); // Вот теперь сюда свалится ошибка

  err.sendStatuc(500);
});

https://tc39.github.io/ecma262/#prod-Keyword
https://tc39.github.io/ecma262/#prod-ExportDeclaration


typeof exports; // => "undefined"

typeof export; // => SyntaxError: Unexpected token export

Т.е. typeof exports — это не SyntaxError, это валидный синтаксис.

Теперь вы знаете, что можно перейти с Webpack-а на нативные модули и даже знаете о существовании lodash-es.

Не совсем понимаю в чем реальный профит:


  • 600 запросов, пусть и HTTP/2. Почему бы этот файл не склеить и не закешировать, ведь библиотеки не так часто обновляют в уже работающем проекте.
  • Если используется не чистый JS, а Flow или TypeScript, все равно придется их чем-то транспилить / компиллить. Это же относится и к минификации.
  • Хоть современны браузеры и быстро обновляются, но всегда будет IE или Safari. А значит нужны полифилы или фолбэки. А раз стоит такой выбор, то почему бы сразу не доунгрейднуть код транспилятором до ES5 и уже отточенных require.js / webpack модулей.

Я люблю модульную систему ESNext, и мне нравится ее спецификация (и строгость этой спеки), но мне кажется что ее миссия уже выполнена, она стандартизировала модули, и окончательно внесла ясность. А вот зачем использовать их нативную реализацию, для меня пока загадка. Или я что-то не понимаю?

Вероятнее всего опечатка, не exports, а export. (exports — это объект экспотра из commonjs / node.js).


const modulesSupported = typeof exports !== undefined;

// =>

const modulesSupported = typeof export !== undefined;
Основной ход обучения взят из официального руководства, но это не дословный перевод, а адаптация руководства, с переписанными примерами с ES5 на TypeScript и измененной структурой проекта. Я также раскрыл некоторые темы более развернуто.

https://habrahabr.ru/post/324894/

А разве можно phaser.js c webgl использовать?

Да, PIXI умеет работать с WebGL


Если да то, phaser.js + babylon.js или phaser.js + three.js можно использовать?

Видел статью, где был пример использования Phaser + Three.js, да и сам Ричард Дэви не раз упоминал его на форуме. Но я сам не пробовал, не думаю, что phaser приспособлен для этого.


Эффект параллакса, только фрейморком phaser.js, можно создать?

Параллакс не зависит от 3D. Эффект можно достичь просто наложив 2 спрайта друг на друга, и передвигать их с разной скоростью.

Не совсем понимаю как его "глобальность" мешает современным сборщикам. Cuncking работает, можно разбивать билд на логические части; TypeScript вообще не парится, что переменная Phaser не импортирована, а глобально.


Единственно, что появляется 3 глобальных переменных: Phaser, PIXI и p2. Но, думаю, это не такая большая беда.


И суда по этому участку кода, автор делает это намеренно.

А будет статья про подготовку игры именно для публикации в PlayMarket/AppStore

В рамках этой серии статей — нет, ее цель познакомить читателя с азами Phaser в связке с TypeScript


Там же как-то ее собирать надо, чтоб вся графика находилась в приложении (извините за терминологию, я абсолютно в этом не разбираюсь, никогда игры не делал)

Это легко делается с помощью PhoneGap или Cordova.
Собственно это и один из способов собрать JavaScript приложение для мобильных устройств, оно же и упакует все ресурсы в APK (или аналог на Iphone) файл.


Для Desktop'а, думаю нужно смотреть в сторону Electron.


Плюс интересует организация управления под телефоны. Вот например в Sligher'е добавили область для пальца, типа джойстика и т.д (там несколько вариантов), посредствам чего это делается?

Это делается обычным спрайтом из 5-9 состояний (спокойствие, джойстик вверх, вниз, вправо, влево и т.д.):


dpad

Взят отсюда
image


+ проверкой, находится ли палец в одном из квадротов (стрелок).

Бесплатный — это $0. А MIT — это свободный, или «опенсорсный». Продавать лицензия MIT формально не запрещает.

Спасибо, исправил. Думаю, так действительно будет более правильно.

Не знаком с API photoshop, но думаю он совсем уж «скриптовый». Phantom — полноценный Web Kit со всеми вытекающими. А это значит, он не ограничивает нас «картинками», можно использовать SVG, WebGL и прочее.

К примеру, так можно рендерить Highcharts в Png и т.д.

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность