Skip to content

Instantly share code, notes, and snippets.

@tonylampada
Created September 15, 2023 18:53
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 tonylampada/16639ddfd2f1c12cbc5d92b4b1df9175 to your computer and use it in GitHub Desktop.
Save tonylampada/16639ddfd2f1c12cbc5d92b4b1df9175 to your computer and use it in GitHub Desktop.
// web framework
function webapp() {
return {
handlers: {},
addRoute(route, fn){
this.handlers[route] = fn;
},
async exec(route, params){
const handler = this.handlers[route];
if (!handler) {
return {status: 404, body: `route not found: ${route}`}
}
return new Promise(async (resolve) => {
try {
await handler(params, {send: ({status, body}) => {
status = status || 200;
body = body || "OK"
resolve({status, body});
}})
} catch (err) {
console.error(`[REQUEST ERROR] - ${route} with params ${params}`, err)
resolve({status: 500, body: "unknown error"})
}
})
}
}
}
// helper "asyncify"
async function sleep(ms) {
// async pause, for dramatic purposes
return new Promise((r) => setTimeout(r, ms));
}
// backend services
const services = {
async loadFooFromDatabase(id) {
await sleep(300)
return {id, name: "foo"};
},
async saveFooToStorage(foo, filename) {
await sleep(300);
const fooData = {id: foo.id, Name: foo.Name, size: foo.Name.length};
console.log(`storage pretend save: ${JSON.stringify(fooData)}`)
const storageId = parseInt(Math.random() * 1E10);
return storageId;
},
async scheduleFooTransfer(storageId) {
await sleep(300);
console.log(`fake pubsub call with storageId ${storageId}`)
const messageId = parseInt(Math.random() * 1E10);
return messageId
}
}
// my app
const myapp = webapp();
myapp.addRoute('/save/foo', savefoo1)
myapp.addRoute('/save/foo2', savefoo2)
function savefoo1(params, res) {
const {id} = params;
// ugly code style
// risk losing track of the stack
// by throwing exceptions into the void
services.loadFooFromDatabase(id).then(foo => {
services.saveFooToStorage(foo, `/path/to/foo/${foo.id}`).then(storageId => {
services.scheduleFooTransfer(storageId).then(messageId => {
console.log(`finished processing foo ${id}. MessageID = ${messageId}`)
res.send({status: 200, body: `OK - foo processed ${id}`})
})
})
})
}
async function savefoo2(params, res) {
const {id} = params;
const foo = await services.loadFooFromDatabase(id)
const storageId = await services.saveFooToStorage(foo, `/path/to/foo/${foo.id}`)
const messageId = await services.scheduleFooTransfer(storageId)
console.log(`finished processing foo ${id}. MessageID = ${messageId}`)
res.send({status: 200, body: `OK - foo processed ${id}`})
}
module.exports = myapp
// r1 = await myapp.exec('/save/foo', {id: 3})
// r2 = await myapp.exec('/save/foo2', {id: 3})
@tonylampada
Copy link
Author

If you're wondering what was the "right" way to solve that problem in the world before async/await,

This is the "right" way to chain promises, so that you can still have a catch-all after them:
https://gist.github.com/tonylampada/192442087b3830d4c7e7698e0d3daaab

It's better than the wrong way, but with async/await it's probably not even worth teaching it :-)

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