-
-
Save Salakar/d49303e2e87ce98a3fb6d928b18aa578 to your computer and use it in GitHub Desktop.
using ES6 Proxy to let Promises/Observables pretend like they're regular values
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
// using ES6 Proxy to let Promises/Observables pretend like they're regular values. | |
// get the mapping function used for async objects | |
let getMapper = (target) => target instanceof Promise ? 'then' : | |
target instanceof Observable ? 'switchMap' : null; | |
// ^ fails if the Observable is in a local namespace e.g. Rx.Observable | |
// bind a value to its object if it's a function | |
let bindFn = (val, obj) => typeof val == 'function' ? val.bind(obj) : val; | |
// the proxy's trap handler | |
let handler = {}; | |
// function invocation | |
handler.apply = (targetFn, that, args) => { | |
// must wrap Proxy target in functions for this `apply` trap :( | |
let target = targetFn(); | |
let mapper = getMapper(target); | |
if(mapper) { // async | |
// transparently map; keep Proxy. | |
let val = target[mapper]((fn) => fn(args)); | |
return new Proxy(() => val, handler); | |
} else { // sync | |
// no-op, ditch proxy | |
return target.apply(that, args); | |
} | |
}; | |
// property access | |
handler.get = (targetFn, prop) => { | |
let target = targetFn(); | |
let value; | |
let mapper = getMapper(target); | |
let bound = bindFn(target[prop], target); | |
if(mapper) { // async | |
if(prop in target) { | |
// ditch Proxy when directly invoking Promise/Observable method | |
return bound; | |
} else { | |
// transparently map; keep Proxy. | |
let value = target[mapper]((o) => bindFn(o[prop], o)); | |
return new Proxy(() => value, handler); | |
} | |
} else { | |
// sync: no-op, ditch proxy | |
return bound; | |
} | |
}; | |
let pretend = (v) => new Proxy(() => v, handler); | |
// now test our shiny `pretend` method. | |
let later = (v) => new Promise((resolve, reject) => setTimeout(() => resolve(v), 1000)); | |
let obj = { greet: (name) => console.log('Hey ' + name) }; | |
let prom = later(obj); | |
let greeter = pretend(prom); | |
// this is a Proxy'd Promise... | |
// yet we can call its methods using traditional syntax. | |
greeter.greet('you'); | |
// ^ look mom, no `then`! | |
let res = greeter.then(() => console.log('sup')); | |
// un-Proxy by calling Promise methods like `then` (which `await` transpiles to AFAIK). | |
// This works similarly for Observables. | |
console.log('res', res); | |
// value: Promise<{ greet }> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment