if you’re reading .then() it’s too late · if we’re doing async work, effects are (almost)...
TRANSCRIPT
![Page 1: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/1.jpg)
If You’re Reading .then() It’s Too Late
Luke Westby
![Page 2: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/2.jpg)
HandlingeffectsinJavaScript
![Page 3: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/3.jpg)
Effect:Anyinteractionwiththe
outsideworld
![Page 4: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/4.jpg)
const request = (url) => { return fetch(url).then((r) => r.json()); };
const getUser = (id) => { return db("users").where({ id }).first() .then((user) => user.id); };
const currentOffset = (el) => { return window.scrollY - el.scrollTop; };
![Page 5: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/5.jpg)
![Page 6: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/6.jpg)
![Page 7: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/7.jpg)
![Page 8: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/8.jpg)
Somethingsreallyshouldbetheresponsibilityofthelanguage
![Page 9: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/9.jpg)
Callbacks
doSomeWork((error, result) => { if (error) respond(error, 500); else respond(result, 200); });
doSomeWork((error, firstResult) => { if (error) return respond(error, 500); else { processFirstResult(firstResult, (secondError, secondResult) => { if (secondError) return respond(secondError, 500); else { if (secondResult.prop) { doFirstBranchWork(secondResult, (firstBranchError, firstBranchResult) => { if (firstBranchError) respond(firstBranchError, 500); else respond(firstBranchResult, 200); }); } else { doSecondBranchWork(secondResult, (secondBranchError, secondBranchResult) => { if (secondBranchError) respond(secondBranchError, 500); else respond(secondBranchError); }); } } }); });
![Page 10: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/10.jpg)
PromisesdoSomeWork() .then((result) => processFirstResult(result)) .then((result) => { return result.prop ? doFirstBranchWork(result) : doSecondBranchWork(result); }) .then((result) => respond(result, 200)) .catch((error) => respond(error, 500));
![Page 11: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/11.jpg)
![Page 12: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/12.jpg)
![Page 13: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/13.jpg)
const myPromise = new Promise((resolve, reject) => { doSomeWorkCallbackStyle((error, result) => { if (error) reject(error); else resolve(result); }); });
}executor
![Page 14: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/14.jpg)
![Page 15: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/15.jpg)
Ifwe’redoingasyncwork,effectsare(almost)alwaysinvolved
Promisesrepresentthecreationofasyncwork
IfaPromiseispresent,itwecanprettysafelyassumethepresenceofaside-effect
![Page 16: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/16.jpg)
side-effects
![Page 17: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/17.jpg)
(user) => user.idThisissupereasytotest:
db(“users").first() .then((user) => user.id)
Thisislesseasytotest:
![Page 18: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/18.jpg)
![Page 19: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/19.jpg)
https://www.youtube.com/watch?v=6EdXaWfoslc
![Page 20: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/20.jpg)
const getUser = (id) => { return db("users").where({ id }).first(); };
vs.
const getUser = (id) => ({ action: "db", table: "users", operations: [ ["where", { id }], ["first"] ] });
![Page 21: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/21.jpg)
const dbRunner = ({ table, operations }) => { const query = db(table); return operations.reduce(/* ... */, query); };
Somewhereelse…
![Page 22: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/22.jpg)
Declareeffectsinapplicationcode
Pauseexecutionoftheapplicationcodetoexecutetheeffect
Resumeapplicationcodewhentheeffecthasproducedaresult
![Page 23: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/23.jpg)
Reacttype ReactDOMElement = { type: string, props: { children: ReactNodeList, className: string, ... }, key: string | boolean | number | null, ref: string | null };
![Page 24: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/24.jpg)
Cycle.js
http://jsbin.com/numuladaqe/1/edit?js,output
Inparticular,lines10-13
![Page 25: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/25.jpg)
const actionHandlers = { [Actions.begin](request) { return Actions.dbCall({ table: “users", operations: [ ["where", { id: request.params.id }], ["first"], ] }); }, [Actions.dbCallSuccess](request, user) { return Actions.respond(user.id, 200); }, [Actions.dbCallFailure](request, error) { return Actions.respond(error, 500); } };
![Page 26: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/26.jpg)
server.route({ method: “GET", path: “/users/{id}", handler(request, reply) { runActions(runners, actionHandlers, request) .then((result) => { reply(result.data).statusCode(result.status); }) .catch((error) => { reply(error.message).statusCode(error.status); }); } });
![Page 27: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/27.jpg)
const actionHandlers = { [Actions.begin](request) { return Actions.dbCall({ table: “users", operations: [ ["where", { id: request.params.id }], ["first"], ] }); }, [Actions.dbCallSuccess](request, user) { return Actions.respond(user.id, 200); }, [Actions.dbCallFailure](request, error) { return Actions.respond(error, 500); } };
const actionHandlers = { [0](request) { return dbCall({ table: “users", operations: [ ["where", { id: request.params.id }], ["first"], ] }); }, [1](request, user) { return respond(user.id, 200); }, error(request, error) { return respond(error, 500); } };
![Page 28: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/28.jpg)
server.route({ method: “GET", path: “/users/{id}", handler(request, reply) { runActions(runners, handler(request)) .then((result) => { reply(result.data).statusCode(result.status); }) .catch((error) => { reply(error.message).statusCode(error.status); }); } });
![Page 29: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/29.jpg)
const handler = function* (request) { try { const user = yield { type: “db", table: “users", operations: [/* ... */] };
return respond(user.id, 200); } catch (error) { respond(error.message, 500); } };
Generators
![Page 30: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/30.jpg)
const iterator = handler({ params: { id: 1 } });
let next = iterator.next(); assertDeepEqual(next.value, { type: "db", /* ... */ });
next = iterator.next({ id: 1, name: "Luke", /* ... */ }); assertDeepEqual(next.value, respond(1, 200));
// or
next = iterator.throw(Error("NOPE!"); assertDeepEqual(next.value, respond("Luke", 500));
![Page 31: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/31.jpg)
![Page 32: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/32.jpg)
![Page 33: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/33.jpg)
Twoproblems:
1.Nestedcallsareuncomfortable2.Parallelizationisn’tagiven
![Page 34: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/34.jpg)
const handler = function* (request) { try { const user = yield { type: “db", table: “users", operations: [/* ... */] };
return respond(user.id, 200); } catch (error) { respond(error.message, 500); } };
![Page 35: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/35.jpg)
const handler = function* (request) { try { const userId = ?? getUserId(request); ?? } catch (error) { respond(error.message, 500); } };
![Page 36: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/36.jpg)
const handler = function* (request) { try { const userId = yield spawn(getUserId, request); } catch (error) { respond(error.message, 500); } };
![Page 37: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/37.jpg)
OnlyonelevelofcontinuationispossiblewithGenerators
Whatifwecouldyielddeeply?
![Page 38: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/38.jpg)
https://esdiscuss.org/topic/one-shot-delimited-continuations-with-effect-handlers
One-shotdelimitedcontinuationswitheffecthandlersSebastianMarkbåge
![Page 39: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/39.jpg)
const funcWithEffect = (request) => { const user = perform { type: “db”, /* ... */ }; return user.id; }
try { const result = funcWithEffect(request); } catch effect -> [{ type, ...details }, continuation] { runners[type](details)
.then((result) => continuation(result)) .catch((error) => { throw error; });
}
![Page 40: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/40.jpg)
Ifthiscanbeimplementedefficiently,itshouldbeimplemented
Again,somethingsreallyshouldbetheresponsibilityofthelanguage
![Page 42: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/42.jpg)
Questions?
![Page 43: If You’re Reading .then() It’s Too Late · If we’re doing async work, effects are (almost) always involved Promises represent the creation of async work If a Promise is present,](https://reader033.vdocuments.site/reader033/viewer/2022042312/5edabab2da2ba853470deeaa/html5/thumbnails/43.jpg)