laxy v1.0.0
laxy

Proxies for lazy loading expensive objects. Lazy + Proxy === Laxy
Install
$ npm install laxyUsage
const laxy = require('laxy');
const proxy = laxy(generatorFn)(...argsToPass);
// generatorFn will only be called once, but not until you interact with the proxy in some way:
proxy();
proxy.foo;
Object.keys(proxy); // etc...
// Can be used as a lazy require
const _ = laxy(require)('lodash');
// lodash won't be loaded until you do something with it:
_.isNumber(3);Basic API
laxy(generatorFn)(...argsToPass)
generatorFn
Type: fn
The function that should be called to generate the object being proxied. This function will be called lazily and only once.
...argsToPass
Type: anything
Any number of arguments may be provided and will be passed to the function if/when it is called.
Providing Type Hints
The Javscript Proxying API sets a few things in stone at the time of Proxy creation (like the response to typeof). Since we are lazy loading, and can't know these at creation time, laxy provides a hint system to help you customize the Proxy to better reflect the object you will return from your generator function. In many cases, you will not care, and the default type hint of func will be sufficient (even if your generator will return an object). Hints are provided with property chaining, the API remains the same:
laxy.func(generatorFn)(...args); // generator returns a function or class
laxy.obj(generatorFn)(...args); // generator returns an object
laxy.arrow(genneratorFn)(...args); // generator returns an arrow function
laxy.class(generatorFn)(...args); // generator *is* a class functionEach of the type hint options are described in detail below:
obj- Indicates your generator function will return an object. If you actually do return a function, you won't be able to invoke it, but you will be able to access and invoke members of the function. Your proxy will respond totypeof proxywith'object'regardless of what the actual proxied type is.func- The default. This is the only option that allows for invocation ofnew(meaning your generator function returns a constructor). It works for most situations (even if you aren't returning a function), with a few caveats:- It will respond to
typeofwithfunction, regardless of the actual underlying type. functions have a non-enumerable, and non-configurableprototypeproperty. The Proxy API insists that non-configurable properties are reflected in the proxy, soObject.getOwnPropertyNames(proxy)will include'prototype'. Note that the property isnon-enumerable, so it won't show up inObject.keys(proxy), etc.
- It will respond to
arrow- Represents an arrow function. It is invocable, but can't be invoked withnew. Does not suffer from the forcedprototypeproperty likefuncdoes.class- While all the other hints suggest what the return type of your generator function will be. Theclasshint declares that your generator function is a class function, and should be invoked withnew. This should not be confused to mean your generator will return a class function (in that case, usefunc);
| Hint | typeof proxy | invocable | with new | Caveats |
|---|---|---|---|---|
obj | 'object' | No | No | |
func | 'function' | Yes | Yes | prototype member is enforced and non-configurable |
arrow | 'function' | Yes | No | Avoids prototype issue, but can't be invoked with new. |
class * | 'object' | No | No | Causes your generator function to be invoked with new. |
Revocable Proxies
The Proxy API allows for revocable proxies. Calling the revoke method will invalidate the proxy, and any future access of the proxy will cause a TypeError. You can chain the revocable modifier to create a revocable proxy.
const {revoke, proxy} = laxy.revocable(generatorFunc)(...args);
// or chain it with a type hint
const {revoke, proxy} = laxy.obj.revocable(generatorFunc)(...args);The frozen Modifier
It's simply not possible for laxy to modify the isExtensible state of the underlying object. Calling Object.preventExtensions or Object.freeze on the proxy will not have the desired effect. Similarly, Object.isExtensible(proxy) will return true, even if your generator will return a non-extensible object. If you will return a frozen object from your generator, you can add the frozen modifier so that Object.isExtensible will correctly return false.
const generatorFunc = () => Object.freeze({foo: 'bar'});
const proxy = laxy(generatorFunc)();
Object.isExtensible(proxy);
//=> true, even though the backing object is frozen
const frozenProxy = laxy.frozen(generatorFunc)();
Object.isExtensible(frozenProxy);
//=> false, as it should beNote that the frozen modifier can be chained onto any of the type hints:
laxy.obj.frozen(fn)(...args);
laxy.arrow.frozen(fn)(...args);
laxy.func.frozen(fn)(...args);
laxy.obj.revocable.frozen(fn)(...args);License
MIT © James Talmage
8 years ago