Skip to content

Instantly share code, notes, and snippets.

@ishiduca
Created April 21, 2018 01:26
Show Gist options
  • Save ishiduca/0f988d7e6512dbd6388b23658179b734 to your computer and use it in GitHub Desktop.
Save ishiduca/0f988d7e6512dbd6388b23658179b734 to your computer and use it in GitHub Desktop.
using observer instead of pull-stream on the Elmish architecture. #inu #tom
module.exports = {
init: function () { return {model: null} },
update: function (model, action) { return {model: model} },
view: function () { return null },
run: function () { return null }
}
const yo = require('yo-yo')
// const defined = require('defined')
const observable = require('./observable')
const start = require('./start')
const main = yo`<div></div>`
const data = {
model: 0,
effect: 'SCHEDULE_TICK'
}
const {models, views} = start({
init () { return data },
update (model, action) {
if (action === 'TICK') {
return {
model: (model + 1) % 60,
effect: 'SCHEDULE_TICK'
}
}
return {model}
},
view (model, actionsUp) {
return yo`<div>${model}</div>`
},
run (effect) {
if (effect === 'SCHEDULE_TICK') {
let s = observable()
setTimeout(() => {
s('TICK')
s(true)
}, 1000)
return s
}
}
})
models().subscribe(m => console.log(m))
views().subscribe(el => yo.update(main, el))
document.body.appendChild(main)
var defined = require('defined')
module.exports = function observable (data) {
data = defined(data, null)
var listeners = []
function accessor (newData) {
data = defined(newData, data)
if (typeof newData !== 'undefined') {
listeners.forEach(function (listener) {
listener(newData)
})
}
return data
}
accessor.subscribe = function subscribe (listener) {
return listeners.push(listener) && listener
}
accessor.unSubscribe = function unSubscribe (listener) {
listeners = listener == null
? [] : listeners.filter(function (f) { return f !== listener })
return listener
}
return accessor
}
var xtend = require('xtend')
var defined = require('defined')
var defaults = require('./defaults')
var observable = require('./observable')
module.exports = function start (app) {
app = xtend(app)
var init = defined(app.init, defaults.init)
var update = defined(app.update, defaults.update)
var view = defined(app.view, defaults.view)
var run = defined(app.run, defaults.run)
var actions = observable()
var states = observable()
var models = observable()
var views = observable()
var effects = observable()
var effectActionsSources = observable()
function actionsUp (action) { actions(action) }
actions.subscribe(function (action) {
states(update.call(app, states().model, action))
})
states.subscribe(function (state) {
models(state.model)
state.effect != null && effects(state.effect)
})
models.subscribe(difference(function (model) {
var el = view.call(app, model, actionsUp)
el != null && views(el)
}))
var notifys = {
actions: actions,
states: states,
models: models,
views: views,
effects: effects,
effectActionsSources: effectActionsSources
}
var sources = {}
Object.keys(notifys).forEach(function (name) {
sources[name] = (
['states', 'models', 'effects', 'views'].indexOf(name) !== -1
) ? replayLastValue(notifys[name]) : function () { return notifys[name] }
})
effects.subscribe(function (effect) {
var actionsSource = run.call(app, effect, sources)
actionsSource != null && effectActionsSources(actionsSource)
})
effectActionsSources.subscribe(function (actionsSource) {
var onActionsSourceSub = actionsSource.subscribe(function (action) {
if (action === true) actionsSource.unSubscribe(onActionsSourceSub)
else actions(action)
})
})
process.nextTick(function () {
states(init.call(app))
})
return xtend(sources, {stop: stop})
function stop () {
Object.keys(notifys).forEach(function (name) {
notifys[name].unSubscribe()
})
}
}
function difference (f, data) {
return function (newData) {
if (typeof newData !== 'undefined' && data !== newData) {
data = newData
f(newData)
}
}
}
function replayLastValue (notify) {
var lastValue
var onSub = notify.subscribe(function (value) {
lastValue = value
})
return function listenWithLastValue () {
var proxy = observable()
notify.subscribe(proxy)
notify.unSubscribe(onSub)
process.nextTick(function () {
if (typeof lastValue !== 'undefined') proxy(lastValue)
})
return proxy
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment