Skip to content

Instantly share code, notes, and snippets.

@Lucifier129
Created October 29, 2020 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lucifier129/ed60d7a7afe6d345edc14a7ced60ce5d to your computer and use it in GitHub Desktop.
Save Lucifier129/ed60d7a7afe6d345edc14a7ced60ce5d to your computer and use it in GitHub Desktop.
const log = (message) => {
return {
__typename: 'log',
message,
};
};
const raise = (message) => {
return {
__typename: 'exception',
message,
};
};
const request = (url, params) => {
return {
__typename: 'request',
url,
params,
};
};
const createState = (initialState) => {
let id = Symbol('state');
return {
get: () => {
return {
__typename: 'get_state',
id,
initialState,
};
},
put: (state) => {
return {
__typename: 'put_state',
id,
state,
};
},
};
};
const run = async (f, handlers = {}) => {
let states = {};
let gen = f();
let result = gen.next();
let getState = (stateEffect) => {
if (states.hasOwnProperty(stateEffect.id)) {
return states[stateEffect.id];
}
states[stateEffect.id] = stateEffect.initialState;
return getState(stateEffect);
};
let putState = (stateEffect) => {
states[stateEffect.id] = stateEffect.state;
return stateEffect.state;
};
while (!result.done) {
let effect = result.value;
if (effect instanceof Promise) {
result = gen.next(await effect)
continue
}
if (effect.__typename === 'get_state') {
result = gen.next(getState(effect));
continue;
}
if (effect.__typename === 'put_state') {
result = gen.next(putState(effect));
continue;
}
let effectType = effect.__typename;
if (handlers.hasOwnProperty(effectType)) {
let called = false;
await handlers[effectType](effect, (value) => {
if (called) return;
called = true;
result = gen.next(value);
});
continue;
}
throw new Error(`Unknown effect: ${effectType}`);
}
return result.value;
};
const Count = createState(0);
const incre = function* (step = 1) {
let count = yield Count.get();
return yield Count.put(count + step);
};
const main = function* (initialCount = 0) {
if (initialCount === 10) {
yield raise(`count should not be equal to 10`);
}
yield Count.put(initialCount);
let count = yield* incre(2);
let transform = yield run(() => incre(2))
yield log(`count: ${count}`);
yield log(`transform count: ${transform} `)
let { data } = yield request('/api', { a: 123 });
return {
count,
data,
};
};
const delay = (duration = 1000) => {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
};
let handlers = {
exception: ({ message }, k) => {
throw new Error(message);
},
request: async ({ url, params }, k) => {
await delay(100);
let response = {
data: {
url,
params,
},
};
k(response);
},
log: ({ message }, k) => {
console.log(message);
k();
},
};
const test = async (count = 0) => {
let result = await run(() => main(count), handlers);
return result;
};
test(3).then((result) => console.log('result', result));
test(10).catch((error) => console.log('error', error));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment