Fractal schizophrenia



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.





, :



  1. yield return β€” , yield* ; , ,
  2. , , 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 β€” , , .







  • ,
  • 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 , , , , β€” .





, , . , .



, .



" β€” " Β©




All Articles