Skip to content

Instantly share code, notes, and snippets.

@Lucifier129
Created June 28, 2018 14:33
Show Gist options
  • Save Lucifier129/64152dc8255c8e3ae17504baf4dbb35f to your computer and use it in GitHub Desktop.
Save Lucifier129/64152dc8255c8e3ae17504baf4dbb35f to your computer and use it in GitHub Desktop.
algebraic effects and handlers for promise and observable
import { interval, isObservable } from 'rxjs'
import { tap } from 'rxjs/operators'
const type = {
isThenable: obj => !!(obj && typeof obj.then === 'function'),
isObservable: obj => !!(obj && isObservable(obj)),
isError: obj => obj instanceof Error,
isObject: obj => obj != null && typeof obj === 'object'
}
const mapValue = (obj, f) =>
Object.keys(obj).reduce((result, key) => {
result[key] = f(obj[key], key)
return result
}, {})
const defaultValue = {}
const createHandler = f => {
if (type.isObject(f)) return mapValue(f, createHandler)
let raised = false
let lastValue = defaultValue
return (...args) => {
if (raised) {
if (lastValue === defaultValue) throw lastValue
return lastValue
}
let value = f(...args)
raised = true
if (type.isThenable(value)) {
value = value.then(v => (lastValue = v))
throw value
}
if (type.isObservable(value)) {
value = value.pipe(tap(v => (lastValue = v)))
throw value
}
lastValue = value
return lastValue
}
}
const withHandler = handler => f => {
let effect = createHandler(handler)
let execute = () => {
try {
f(effect)
} catch (target) {
if (target === defaultValue) return
if (type.isError(target)) throw target
if (type.isThenable(target)) return target.then(execute)
if (type.isObservable(target)) return target.subscribe(execute)
}
}
execute()
}
const fetchJSON = url => fetch(url).then(res => res.json())
const run = withHandler({ interval, fetchJSON })
run(effects => {
let { fetchJSON, interval } = effects
let data = fetchJSON('https://api.github.com/repos/zeit/next.js')
let count = interval(1000 / 60)
let angle = count % 360
let root = document.getElementById('root')
root.style.transform = `rotate(${angle}deg)`
root.innerHTML = data.stargazers_count
})
@Lucifier129
Copy link
Author

Edit mz6o0onzzp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment