Last active
June 29, 2018 19:03
-
-
Save mrozbarry/1936ffa25cf67474ebb282b4ee0aca99 to your computer and use it in GitHub Desktop.
A tight functional-reactive update loop for Node.JS, inspired by Elm, Hyperapp, and Redux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const nodeEnv = { | |
defer: (fn) => process.nextTick(fn), | |
}; | |
const browserEnv = { | |
defer: (fn) => setTimeout(fn, 0), | |
}; | |
const create = (update, subscriptions = [], env = browserEnv) => { | |
let state = update(undefined, {}); | |
const actionQueue = []; | |
const waitForIdle = () => new Promise((resolve) => { | |
if (actionQueue.length === 0) { | |
resolve(); | |
return; | |
} | |
setTimeout(() => { | |
waitForIdle().then(resolve); | |
}, 1); | |
}); | |
const nextAction = () => { | |
if (actionQueue.length === 0) return; | |
const messageAndParams = actionQueue.shift(); | |
state = update(state, messageAndParams, effect); | |
env.defer(nextAction); | |
}; | |
const effect = (message, params) => { | |
const starved = actionQueue.length === 0; | |
actionQueue.push({ message, params }); | |
if (starved) { | |
nextAction(); | |
} | |
}; | |
const getState = () => { | |
return state; | |
}; | |
const waitForState = (condition) => new Promise((resolve) => { | |
if (condition(state)) { | |
resolve(state); | |
return; | |
} | |
setTimeout(() => waitForState(condition).then(resolve), 1); | |
}); | |
const addSubscription = (subscription) => { | |
subscription(effect); | |
}; | |
subscriptions.forEach((subscription) => { | |
addSubscription(subscription); | |
}); | |
return { | |
getState, | |
waitForIdle, | |
waitForState, | |
effect, | |
}; | |
}; | |
window.FrpApp = { create, nodeEnv, browserEnv } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const App = window.FrpApp; | |
const messagesReducer = (messages = [], { message, params }, trigger) => { | |
switch (message) { | |
case 'ADD_MESSAGE': | |
return [...messages, params.message]; | |
case 'REMOVE_MESSAGES': | |
return messages.filter(message => message!== params.message); | |
} | |
} | |
const update = (state = {}, { message, params }, trigger) => { | |
return { | |
messages: messagesReducer(state.messages, { message, params }, trigger), | |
} | |
}; | |
const thatReallyBlanksMyBlankSub = count => (trigger) => { | |
const fetchIt = (remaining) => { | |
if (remaining === 0) return; | |
fetch('https://api.chew.pro/trbmb') | |
.then((response) => response.json()) | |
.then((quotes) => trigger('ADD_MESSAGE', { message: quotes[0] })) | |
.then(() => { | |
setTimeout(fetchIt, 10000, remaining - 1); | |
}); | |
} | |
fetchIt(count) | |
}; | |
const instance = App.create(update, [thatReallyBlanksMyBlankSub(5)]); | |
instance | |
.waitForState((state) => state.messages.length === 5) | |
.then((state) => console.log('State snapshot', { ...state });// Should have 5 different That really _____s my ____. quotes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment