Created
October 29, 2020 14:38
-
-
Save Lucifier129/ed60d7a7afe6d345edc14a7ced60ce5d to your computer and use it in GitHub Desktop.
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 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