Comments 18
имхо, особенно полезны, когда нужно из разных источников собирать данные в одно целое)
да и конечные автоматы не теряют своей актуальности.
особенно полезны, когда нужно из разных источников собирать данные в одно целое)
Что-то типа Promise.all()
?
Может, конечно, такие задачи и не часто встречаются, но когда встречаются — генераторы очень быстро снимают головную боль)
Я бы не согласился по поводу применять, redux-saga позволяет легко писать тестируемый код на генераторах, и они оказываются проще, чем rxjs подход в ngrx.
Если речь идет о библиотеке co, то она была создана до того как async/await был добавлены в nodejs и реализовывала возможность писать код без callback hell-а.
После появления async/await необходимость в co отпала, самым популярным фреймворком, который популяризировал использование co был koajs v1.x. Новая версия koajs v2.x на использование генераторов выдает «warning» с «deprecated».
Суть этой истории сводится к тому что не нужно использовать генераторы не по назначению, а не к принципиальному отказу от использования генераторов.
При этом, на самом деле, все любители извращений тайно потирали руки и ждали реализации генераторов ради того, чтобы костылить на них эмуляцию async/await. И сразу после появления сделали пачку библиотек, которые это делают. Получается, возможность генераторов изначально все планировали использовать не по назначению.
Другими словами, добавили фичу, которую все используют для других целей. Может быть стоило сразу использовать async/await и забить на эти генераторы?
Но в целом согласен. Кстати, в C++ посмотрели на это, да в Coroutines TS генераторы и асинхронные функции ввели одновременно, причем именно yield оказалось реализовано через await, а не как обычно.
Например, с помощью async/await нельзя сделать асинхронный action в mobx без боли (а с помощью генератора — можно)
А можно пример? Просто интересно, что там такое хитрое.
Вот так это делается с async/await:
@action
async foo() {
const result = await fetch(...);
const data = await result.json();
runInAction(() => {
// без runInAction будет лишний рендер, потому что mobx не может отловить асинхронные продолжения и обернуть их в транзакцию
this.bar = data.bar;
this.baz = data.baz;
});
}
А вот так это делается с генератором:
foo = flow(function * () {
const result = yield fetch(...);
const data = yield result.json();
// поскольку mobx сама управляет вызовами продолжений нет никаких проблем обернуть каждое в транзакцию автоматически, runInAction не нужен
this.bar = data.bar;
this.baz = data.baz;
})
Я правильно понимаю суть? В варианте с await если убрать runInAction
, то после this.bar = ;
мы получим render, а потом ещё и после this.baz = ;
, т.к. рендер синхронный? А в случае *
mobx не обновляет при детекте изменений до тех пор, пока не получит через yield что-нибудь асинхронное, или генератор просто не кончится? Т.е. тут решает все проблемы ручная обработка каждого yield, позволяя сделать больше, чем написано в коде?
github.com/tc39/proposal-async-iteration
реализация хелпера
Чёж пример async/await не показали, ради которого всё писалось, а какой-то устаревший co есть, как-будто старая статья...
До сих пор мы, работая с JS-функциями, ожидали, что они, будучи вызванными, просто выполняются от начала до конца
Ну и что? А теперь появился новый вид функции. Если чего-то раньше не было, значит никогда это не использовать?
Ссылки на async/await на мой взгляд притянуты за уши. Да когда не было async/await можно было писать aync/await-образный код при помощи генераторов, но вообще они не об этом.
Генератор это вещь которая может вернуть коллекцию чего-то без предварительного выделения памяти под коллекцию, в том числе коллекция может быть бесконечной.
В других языках подобные конструкции есть давным давно, используются например для получения информации из БД.
Другой пример при помощи генератора можно создавать интерфейс для итерации по нескольким существующим коллекциям.
О генераторах в JavaScript ES6, и о том, почему изучать их необязательно