Non, je ne suis pas malade. Du moins c'est ce que dit la voix dans ma tête. Je suis toxicomane. Je suis sur l'aiguille depuis plus de 15 ans. J'utilise beaucoup, dur, jusqu'à ce que je m'évanouisse. J'en suis arrivé au point que dernièrement, je n'ai pas eu honte de mes amis, de ma femme ou de mes enfants ... Deux enfants! Je n'aime pas le badazhenny, j'aime propre, sans impuretés. J'ai beaucoup essayé au fil des ans, mais récemment j'ai arrêté de chercher. C'est drôle de réaliser que la même chose vous procure à la fois de la douleur et de la joie. J'aimerais aller en cure, j'en ai même envie, je sais même laquelle. Connaissez-vous ceux où vous continuez à utiliser, mais sous 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 , , , , — .
, , . , .
, .
" — " ©