asdf404
0

Когда вызывается return или мы выходим из генератора, то всё равно возвращается Promise, содержащий IteratorResult. Вот пример с кодом:


async function* values () {
  yield 1
  yield 2
}

function handle () {
  const iter = values()
  console.log(iter.next()) // Promise { value: 1, done: false }
  console.log(iter.next()) // Promise { value: 2, done: false }
  // следующего элемента нет
  console.log(iter.next()) // Promise { value: undefined, done: true }
}
handle()

Т.е. последний промис разрешается сразу и возвращает done = true. Вы можете запустить этот код и проверить самостоятельно.


Зачем тут чушь пишите?

В каком месте я написал чушь?

asdf404
0
А если сильно извратиться — можно ли чисто теоретически снаружи повлиять на наш генератор

Да, вы можете в next() передать какое-нибудь значение:


function* generator () {
  let value = yield 'Hi!'
  console.log('Hello %s!', value)
}

const iterator = generator()
console.log(iterator.next().value) // выведет "Hi!"
iterator.next('World') // выведет "Hello World!"

Таким образом можно передать генератору что угодно.

asdf404
–1
А снаружи-то как вовремя узнать что больше элементов не будет?

Снаружи "вовремя" будет тогда, когда зарезолвится промис, т.к. пока это не произойдёт ваш цикл не сможет пойти дальше. А когда промис резолвится, то он возвращает состояние итератора, где указано завершился итератор или нет.


Чему будет равно свойство done итератора во время выполнения оператора await в генераторе?

Оно будет равно false. Станет равным true лишь при выходе из функции-генератора явно (по return) или неявно (кончилось тело функции).

asdf404
0

Сейчас и для обычных итераторов их нельзя применить. Для этого сначала нужно преобразовать в массив (с помощью Array.from или spread оператора [ ...iterable ]), а потом над ним уже совершать операции.
В качестве эксперимента я пишу библиотеку, которая добавляет эти методы прямо к итератору (изменяет его прототип, как делает SugarJS), но она далека от завершения, к тому же есть множество более качественных альтернатив: Wu, Lazy.JS и т.д.

asdf404
+3

Давайте избавимся от for-await-of и посмотрим как это можно обработать вручную. Допустим, у нас есть удалённая очередь queue с несколькими элементами.
Пример для IteratorResult<Promise>:


const queue = ... // queue это итератор
while (true) {
  const { value, done } = queue.next()
  // done всегда будет false, т.к. из генератора синхронно(!) мы не можем узнать закончилась ли очередь
  const result = await value // здесь мы дожидаемся разрешения value
  if (result === null) { break } // вот здесь нужно проверить, что нам вернулось пустое значение. Но дело в том, что null может быть вполне валидным значением, а не индикатором пустой очереди
  // обрабатываем  result; следующая итерация
}

Как видите, этот подход имеет недостаток — у нас нет четкого понимания, что очередь пуста. Мы не можем трактовать null как конец, если только не приняли некое соглашение, что null — это всегда конец очереди.


В случае с Promise<IteratorResult> всё несколько иначе:


const queue = ...
while (true) {
  const { value, done } = await queue.next() // здесь у нас есть Promise, который возвращает текущее состояние итератора
  if (done) { break } // и есть четкое понимание когда стоит прекратить цикл
  // обрабатываем value; следующая итерация
}

Т.е. при подходе Promise<IteratorResult> у нас есть возможность без всяких соглашений четко дать понять, что очередь пуста, можно выходить из цикла. queue, например, может при каждом вызове next() помимо получения элемента спрашивать у очереди сколько элементов осталось и при значении 0 вернуть done = true, чтобы прервать цикл и не создать последующих запросов.

asdf404
0

Судя по всему, поддержку недавно добавили в V8. Не использую Chrome, так что не могу проверить.

asdf404
+2

Для этого придуман Git LFS.

asdf404
+5
php/python/ruby etc. сами по себе интерпретируемые языки

неправда. Они компилируются в байткод, который потом исполняется виртуальной машиной.


умудряются напихать каких-то бешеных абстракций

которые нужны, чтобы код от разных вендоров работал "искаропки" и имел одинаковые интерфейсы.


ORM — «птичий» язык доступа к БД, зачем когда есть SQL

затем, чтобы вы могли выбрать данные из одной СУБД (например MySQL), "сджойнить" их с данными из другой (например MongoDB, мне это приходилось делать), закешировать на некоторое время, и всё это без кучи бойлерплейт кода каждый раз. Для любителей SQL есть Query Builder'ы, которые генерят запросы для разных диалектов SQL.


Шаблонизаторы — еще один птичий язык

а что вы предлагаете взамен? Только PHP, насколько я знаю, позволяет инлайнить код прямо в HTML, остальным языкам (React не рассматриваем) нужны шаблонизаторы. Хорошо, что есть широкоиспользуемые языки для шаблонов (Mustache, Jade/Pug и т.д.), которые позволяют не учить 100500 разных синтаксисов, а везде делать одинаково (имел несчастье работать с angular1 на фронте и php на бэкенде, один шаблонизатор немного сгладил боль).


переаллокации памяти и перекачивание данных между буферами

оверхед неизбежен, но это плата за скорость разработки.


как работает веб сервер — активизируется заново для каждого обращения

это не так. Какой-нибудь apache ещё может порождать по процессу на запрос, но, к счастью, к нему прибегают всё реже. nginx, например, имеет пул процессов, которые обрабатывают запросы пользователей. Здесь можно мне возразить, что процесс всё же порождается, но только это не веб-сервер, а какой-нибудь PHP-интерпретатор. Да, это так, но только если вы не используете fastCGI. В остальных языках чаще используется какой-нибудь встроенный в веб-фреймворк (Node.JS, Ruby Unicorn и т.д.) HTTP сервер (хотя мне тоже такое решение не особо нравится).


на Си — вполне разумное решение

нет. Это очень опасное занятие. Даже матёрые программисты допускают глупые ошибки, которые могут очень дорого обойтись. Все эти "интерпретируемые языки" зачастую неплохо отлажены и не имеют таких багов, по крайней мере, их сложнее эксплуатировать. Если хотите убер-скорость, но чтобы было безопасно, взгляните на Rust, с его zero-cost abstractions, и какой-нибудь веб-фреймворк для него или на Go и его решения.


P.S. Сам я веб-разработчик и сейчас, как раз, изучаю Rust, но всё равно не стал бы на нём писать веб.

asdf404
+2

Пункты 1, 2, 5, 6, 9 и 10 также работают и в ФФ. Пункт 7 inspect(...) в ФФ делает тоже самое, что и dir(...) в Хроме.
А ещё, при выборе элемента в инспекторе он становится доступен как $0 в консоли (ФФ и Хром).
А все обработчики событий (пункт 3) в ФФ можно посмотреть, если в инспекторе рядом с элементом кликнуть на кнопочку ev.

asdf404
0

Ни разу не приходилось запускать node с sudo за время использования nvm, а до этого приходилось лишь пару раз. Но, если бы пришлось, то скорее всего прописал бы полный путь до бинарника (sudo ~<username>/.nvm/versions/node/<version>/bin/node). Да, неудобно, но если это не разовый запуск (например крон), то можно создать симлинк в /usr/bin или создать алиас или скрипт:


#!/path/to/node

console.log('Hello World!')

Сейчас вообще стараюсь не запускать проекты на хост-машине напрямую. Толкаю всё в докер, а с хост машины дёргается docker-compose exec some-periodic-task node /src/task.js — криво, неудобно, но лучше не придумал.

asdf404
0
Ещё можно использовать NVM:
nvm install v7.0.0
nvm alias default v7.0.0
asdf404
+1
По поводу первого пункта мы можем долго спорить. Всё же я считаю, что если вы храните любые данные, пришедшие от юзера, сколько бы и какими бы они ни были, то это, мягко говоря, странно. Когда вы проектируете сервис, то с большой долей вероятности знаете чего хотите и примерно представляете, что будет дальше. Исходя из этого проектируете модель данных. Вообще у меня есть сомнения, что мы говорим об одном и том же, изначально мне показалось, что вы предлагаете сохранять любые данные от юзера (100-мегабайтный JSON, картинка с котятами и т.п.) как значение, а потом из него пытаться выбрать нужные поля.

По поводу "не сохраняет". Это не важно. Даже, если злоумышленник может получить список всех юзеров сервиса (включая их личные данные), то это уже плохо.
asdf404
+5
Фильтровать при записи нужно как раз для того, чтобы не тратить каждый раз ресурсы на фильтрацию при отдаче. А ещё это в какой-то мере поможет уберечься от NoSQL-иъекций.
asdf404
+6
Разные потребности бывают :)
asdf404
+2
Можно ещё вот так:
Array
  .apply(null, new Array(10))
  .map((_, i) => i);
asdf404
+1
Пока что только JS (Express, Restify, коллега настойчиво советует Loopback) и PHP (legacy код).
asdf404
+1
Спасибо за ответ.

Вы спрашиваете что-то вроде: «а как мне выкинуть из Catberry основную часть и использовать вместо выкинутого куска React, но так чтобы вы все остальное работало также»

Нет же. Я просто сказал, что мне хочется именно реакт с его компонентами.

текущая архитектура и подход React никогда не позволят ему реализовать прогрессивный рендеринг

К сожалению приходится чем-то жертвовать.
asdf404
+1
API можно/нужно писать на том, что удобнее. Главное — HTTP интерфейс для клиента. У себя в pet-project я решил разделить renderer-app и API на кучку модных нынче микросервисов, которые общаются между собой и клиентом по HTTP.
asdf404
+1
Каким-то чудом Este.JS обошел меня стороной. Выглядит очень интересным, спасибо, обязательно утащу оттуда какие-нибудь решения. Насчёт него пока ничего не могу сказать, т.к. внутрь особо не смотрел. Но интересно, как они победили синглтоны и прочие грабли.
На Catberry смотрел несколько месяцев назад, но тогда мне не понравилось, что нужно компоненты держать в catberry_* каталогах, меня крайне раздражают вендор-префиксы. Ещё хотелось для шаблонизации использовать именно React, т.к. он чисто внешне близок к HTML — опять же, на мой вкус.
Ещё, я раньше не сталкивался с термином progressive rendering в данном контексте, можете немного пояснить его?

P.S. Думаю, по поводу Catberry pragmadash лучше может ответить.
asdf404
0
Да, с виду это немного странно. Но суть здесь в том, что на один Store может быть подписано несколько компонентов, и при его обновлении, обновятся все связанные компоненты.
asdf404
0
MemoryStorage, например, не должен ничего знать о HTTP и, тем более, не должен бросать HTTP ошибку.
Ошибки в app.js лучше проверять одним try-catch блоком, чтобы не возникало повисших соединений.
Ещё в MemoryStorage мы явно возвращаем Promise. Это можно избежать, если функция явно объявлена как async.
Ну и надо писать больше тестов :)

Уверен, есть ещё недочёты, но пока не могу их вспомнить.
asdf404
+3
По теме могу порекомендовать блог 2ality (en), его автор довольно подробно пишет о новинках из ES6.
asdf404
+1
По поводу webpack'а не подскажу. Решение специально пока что не искал. По поводу вопросов:

1. большой проект у меня пока что только пишется, но уже могу сказать, что некоторые части лучше выносить в отдельные модули или хотя бы папки (отделить, например блог, галлерею и т.п., от остального сайта).
2. из подводных камней, некоторые неожиданные проблемы с async/await, но о них я написал в статье (про заверните в try-catch иначе не увидите ошибок). Также недавно столкнулся с проблемой интернационализации приложения с помощью react-intl. Всё в целом хорошо, но хранение переводов — небольшая боль. Нет дефолтных переводов, надо везде таскать все переводы для текущего состояния иначе ловим исключения. А ещё нужно приучить себя всегда закрывать теги: <MyComponent /> — работает, <MyComponent></MyComponent> — тоже работает, <MyComponent> (не закрыл) — не скомпилится. И ещё одно, вы могли заметить, что при рендеринге на сервере делается запрос к API, и после рендеринга и запуска скриптов на клиенте делается снова такой же запрос. Я сейчас работаю над устранением этого досадного бага. По итогам намерен написать статью. Вы можете погуглить решения по словам rehydrate/dehydrate (так называлось это в fluxible) или же serialize/unserialize. Автор flummox уже вроде как запилил фикс, Но я ещё не смотрел.
3. babel просто транслирует ES6/ES7 → ES5, он не выполняет код сам. Node.JS шустрая, основной затык обычно в запросах к БД. А вот с React на сервере уже не всё так хорошо. Синтетические тесты (ab -c 5 -t 10 ...) TODO списка на моём i7 с 8GiB памяти показали всего лишь около 200RPS, что не очень плохо, если сравнивать с каким-нибудь PHP. Но довольно медленно, если сравнить с другими шаблонизаторами на Node.JS. И при увеличении количества компонентов, которые рендерятся для текущего состояния, производительность продолжает падать. Этого можно избежать в некоторых случаях, если использовать некоторые оптимизации.
4. серебрянной пули не существует :) Уже давно существуют всякие Meteor'ы, Derby.JS и т.д. Но это полноценные фреймворки и иногда с ними нужно бороться, чтобы сделать что-то нестандартное (сам не работал, но знающие люди так говорят).

Желаю удачи в вашем проекте :)
asdf404
0
Это такое гибридное (хотя это не совсем правильный термин) приложение, которое использует один и тот же код для рендеринга на клиенте (в данном случае в браузере) и на сервере. Это позволяет не дублировать логику и шаблоны, как в случае с обычными приложениями. Это можно проиллюстрировать такой картинкой:
Картинка
image