No, I'm not sick. At least that's what the voice in my head says. I'm a drug addict. I have been on a needle for over 15 years. I use a lot, hard, until I faint. I have come to the point that lately I have not been ashamed of my friends, my wife, or my children ... Two children! I do not like badazhenny, I like clean, without impurities. I've tried a lot over the years, but recently I stopped looking. It's funny to realize that you get both pain and joy from the same thing. I would like to go to treatment, I even want to, I even know which one. Do you know those where you continue to use, but under supervision?
typescript. β . , , . , , , , . -, , , , - . , , - , , ...
, es- β . ruby
javascript
, , - β yield
? ! , β : ? ? /? Oh My God!
. , , - , , , . , , , , yield
yield
, , - . , . - , , ...
-. β react + mobx. , / , , , , , , , , β¦ , , β , , , .
- . MV*
, β . β *
! ? β , M
, V
, , , !
, typescript. , , Maximum call stack size exceeded
β ? , , , , .
. . , , . Html- β , ? ? ? , , β , β β , ...
- " " β , , , . : " , β " β β "! !". ! ?)
- . . , , , , , . ? , β , , , , ? β 19 , , 1844 , 1862 , , . . , , . , - ? ? , , , , β¦ β¦ ? ? ?
! ! , , - . , . , . β , .
, , 3 , ~800 git- . yield*
. -, . return
? , , , .
async function* SiriusA() {
return '*A' //
}
async function* SiriusB() {
return '*B' //
}
async function* Sirius() {
// ['*A', '*B']
return [yield* SiriusA(), yield* SiriusB()]
}
async function* CanisMajor() {
const sirius = yield* Sirius() // ['*A', '*B']
// -
}
-. : " ? " β , . yield*
. , return
- " " yield
-, β , , , . β , : " ", ~300 . , , - - , , . .
, . , , β . , , β .
, , , .., - , . β , .
@fract/core
β β , : fractal
fraction
. , . , , npm yield*
.
Hello world
, ,
import { fractal, fraction } from '@fract/core'
const Title = fraction('Hello world')
const HelloWorld = fractal(async function* () {
while (true) yield `App: ${yield* Title}`
})
, β , . β , , .use(data)
.
yield
, yield*
, β , yield*
β , yield
. pull & push.
, :
-
yield
return
β ,yield*
; , , - , ,
yield
, ;return
return
, yield
β , "" .
, . , .
interface Frame<T> {
data: T;
}
, . , - , .
interface LiveFrame<T> extends Frame<T> {
next: Promise<LiveFrame<T>>;
}
β , : .
exec
live
. ( ) , .
import { exec, live } from '@fract/core'
exec<T>(target: Fractal<T> | AsyncGenerator<T>): Promise<Frame<T>>
, .
const frame = await exec(HelloWorld)
frame.data // 'App: Hello world'
live<T>(target: Fractal<T> | AsyncGenerator<T>): Promise<LiveFrame<T>>
, .
const frame = await live(HelloWorld)
frame.data // 'App: Hello world'
Title.use('Fractal Demo')
const nextFrame = await frame.next
nextFrame.data // 'App: Fractal Demo'
, ,
const Name = fraction('John')
const Age = fraction(33)
const Balance = fraction(100)
const Card = fractal(async function* () {
while (true) {
yield {
balance: yield* Balance,
}
}
})
const User = fractal(async function* () {
while (true) {
yield {
name: yield* Name,
age: yield* Age,
card: yield* Card,
}
}
})
const frame = await exec(Balance)
frame.data //> 100
const frame = await exec(Card)
frame.data //> {balance: 100}
const frame = await exec(User)
frame.data
/*
> {
name: 'John',
age: 33,
wallet: {
balance: 100
}
}
*/
exec
, live
β
const frame = await live(User)
console.log(frame.data)
/*
> {
name: 'John',
age: 33,
card: {
balance: 100
}
}
*/
Name.use('Barry')
Balance.use(200)
const nextFrame = await frame.next
console.log(nextFrame.data)
/*
> {
name: 'Barry',
age: 33,
card: {
balance: 200
}
}
*/
, , User
( ), undefined
( )
const App = fractal(async function* () {
while (true) {
console.log(yield* User)
yield
}
})
live(App) //
, β .
, , β . , , β Promise<LiveFrame<T>>[]
, racers
, , Promise.race(racers)
β β racer
, racers
β .
Promise.race([
// level 1
Promise.race([/* ... */]),
Promise.race([/* ... */]),
Promise.race([
// level 2
Promise.race([/* ... */]),
Promise.race([/* ... */]),
Promise.race([/* ... */]),
Promise.race([/* ... */]),
Promise.race([/* ... */]),
Promise.race([
// level 3
Promise.race([/* ... */]),
Promise.race([/* ... */])
])
])
])
β " " , . " " , . ,
const Name = fraction('John')
const User = fractal(async function* () {
while (true) {
yield `User ${yield* Name}`
}
})
const Title = fraction('Hello')
const Post = fractal(async function* () {
while (true) {
delay(5000) // -
yield `Post ${yield* Title}`
}
})
const App = fractal(async function* () {
while (true) {
console.log(`App | ${yield* User} | ${yield* Post}`)
yield
}
})
live(App)
//> 'App | User John | Post Hello'
Name.use('Barry')
Title.use('Bye')
//> 'App | User Barry | Post Hello'
// 5
//> 'App | User Barry | Post Bye'
Name
Title
, User
Post
, User
, App
Post
β App
, Post
. App
, Post
. , "" .
. , . tmp(data)
, yield
.
β "". , -, .
import { fractal, tmp } from '@fract/core'
const User = fractal(async function* () {
yield tmp('Loading...')
delay(5000) // -
while (true) {
yield `User John`
}
})
const App = fractal(async function* () {
while (true) {
console.log(yield* User)
yield
}
})
live(App)
//> 'Loading...'
// 5
//> 'User John'
User
"", , .. - . , User
'Loading...'
, , .. yield tmp(...)
, .
β , , -
import { fractal, tmp } from '@fract/core'
const Timer = fractal(async function* () {
let i = 0
while (true) {
yield tmp(i++)
await new Promise((r) => setTimeout(r, 1000))
}
})
const App = fractal(async function* () {
while (true) {
console.log(yield* Timer)
yield
}
})
live(App)
//> 0
//> 1
//> 2
//> ...
Timer
i
, i
, 1 . β , , .use(data)
, .
, . , β .
newEditor
, , . Manager
, ProfileId
.
function newEditor(id) {
return fractal(async function* () {
const { name } = await loadUserInfo(id)
const Name = fraction(name)
while (true) {
// -
//
yield <input
placeholder="Input name"
value={yield* Name}
onChange={(e) => Name.use(e.target.value)}
/>
}
})
}
const ProfileId = fraction(1)
const Manager = fractal(async function* () {
while (true) {
const id = yield* ProfileId
const Editor = newEditor(id)
yield Editor // <-- Editor
}
})
const App = fractal(async function* () {
while (true) {
yield yield* Manager
}
})
- , - , Name
. while(true)
App
, Manager
. Editor
, .
Manager
ProfileId
. Manager
, Editor
.
, β ProfileId
- , Editor
, id
. .
const ProfileId = fraction(1)
const Manager = fractal(async function* () {
let lastProfileId
let Editor
while (true) {
const id = yield* ProfileId
if (id !== lastProfileId) {
lastProfileId = id
Editor = newEditor(id)
}
yield yield* Editor
}
})
, .
const BarryName = fractal(async function* () {
while (true) yield 'Barry'
})
const Name = fraction('John')
const App = fractal(async function* () {
while (true) {
console.log(yield* Name)
yield
}
})
live(App)
//> 'John'
Name.use(BarryName)
//> 'Barry'
β , yield BarryName
.
, , . , . .
import { factor } from '@fract/core'
const API_VERSION = factor('v2') // 'v2' | 'v3'
// ^^^^
/* */
yield* API_VERSION('v3') //
yield* API_VERSION // 'v3' -
yield* API_VERSION.is('v3') // boolean -
//
// c
yield* API_VERSION()
yield* API_VERSION // 'v2'
, . , api API_VERSION
api .
const Page = fractal(async function* () {
const apiVersion = yield* API_VERSION
while (true) {
yield `Work on api "${apiVersion}"`
}
})
const Modern = fractal(async function* () {
yield* API_VERSION('v3')
// api v3
while (true) {
yield yield* Page
}
})
const Legacy = fractal(async function* () {
yield* API_VERSION('v2')
// api v2
while (true) {
yield yield* Page
}
})
const App = fractal(async function* () {
while (true) {
console.log(`
Modern: ${yield* Modern}
Legacy: ${yield* Legacy}
`)
yield
}
})
live(App)
/*
> `
Modern: Work on api "v3"
Legacy: Work on api "v2"
`
*/
! , , ,
const Top = fractal(async function* () {
yield* API_VERSION('v3')
while (true) {
yield yield* Middle
}
})
const Middle = fractal(async function* () {
yield* API_VERSION // 'v3' - Top
yield* API_VERSION('v2') // ,
yield* API_VERSION // 'v3'
while (true) {
yield yield* Bottom
}
})
const Bottom = fractal(async function* () {
yield* API_VERSION // 'v2' - Middle
while (true) {
yield /*...*/
}
})
β , . , , , .
const APP_STORE = 'APP'
function newApp({ name = 'Hello world' } /* AppState {name: string} */) {
const Name = fraction(name)
return fractal(async function* App() {
while (true) {
switch (yield* MODE) {
case 'asString':
yield `App ${yield* Name}`
continue
case 'asData':
yield { name: yield* Name } // as AppState {name: string}
continue
}
}
})
}
const Dispatcher = fractal(async function* () {
//
const data = JSON.parse(localStorage.getItem(APP_STORE) || '{}')
//
const App = newApp(data)
// 'asString'
const AsString = fractal(async function* () {
yield* MODE('asString')
while (true) yield yield* App
})
// 'asData'
const AsData = fractal(async function* () {
yield* MODE('asData')
while (true) yield yield* App
})
while (true) {
const asString = yield* AsString //
const asData = yield* AsData //
//
console.log(asString)
//
localStorage.setItem(APP_STORE, JSON.stringify(asData))
yield
}
})
: App
MODE
, AsString
AsData
, Dispatcher
. , β , .
( ). β , , β , . β , . , , api ..
MV* MVVM MVP
, MV* MVVM MVP .. . , ,
β , , β .
javascript , , .
import { fractal, factor } from '@fract/core'
// app.js
export const API_URI = factor()
export const THEME = factor('light')
export const App = fractal(async function* () {
const apiUri = yield* API_URI
const theme = yield* THEME
if (!apiUri) {
//
throw new Error('Factor API_URI is not defined')
}
while (true) {
/*...*/
}
})
, .
code splitting
, await
. , " " . β , js , . , ...
, . , ,
, , , (). , , , β , β , .
, , webpack, ,
// ./user.js
export const User = fractal(async function* () {
while (true) yield `User John`
})
// ./app.js
export const App = fractal(async function* () {
// ,
const { User } = await import('./user')
while (true) yield `User ${yield* User}`
})
, , , IntelliSense .
, , TodoMVC. , , β¦ β , , , . - β . , β . - , , , , . ...
. , , , , , , , β . , , .
, . , . react
styled-components
β , , .
- Todos β
- Loadable β , , ,
yield tmp(...)
, , , - Factors β . , . .
- Antistress β , , . , , . β , β , β . ,
- ,
-
jsx -> html
,react
, ,diff
, - β ? , , ,
-
grahpql
, - -yield* gql'...'
- open source β ,
- :) , β readme
, - noname- , , , , .
, , - , - react- , @fract/react-alive
import { fractal } from '@fract/core'
import { Alive } from '@fract/react-alive'
const App = fractal(async function* () {
while (true) {
yield <div>Hello world</div>
}
})
function Render() {
return <Alive target={App} />
}
β , , yield*
? @fract/browser-pathname
. , window.location.pathname
, redirect(p: string)
. , , , -.
β . , , . , react , , , , β .
, , . , .
, .
" β " Β©