In this question : How to add a custom property or method to a promise? there are simple solutions regarding how to "add properties" to a promise function when the properties are known in advance.
For the clientside-require
module I am attempting to enable packages that the require()
function loads to append their own properties to the promise that require()
returns. For example, to enable this:
var promise_view_loader = require("clientside-view-loader")
promise_view_loader_package
.load("clientside-view-modal-login_signup")
.generate()
.then((modal)=>{
document.body.appendChild(modal);
modal.show("login");
})
or this
var promies_request_package = require("clientside-request")
promies_request_package
.request("https://google.com")
.then((response)=>{
console.log(response)
})
The problem is that each of these packages we are requiring should be able to define their own custom properties. In other words, we do not know the properties synchronously. First we need to resolve promise_module_properties
and then based on those properties the properties of the promise produced by require
must be modified.
Is this possible?
As Bergi noted, just because we can do this does not mean we should. In fact, i highly recommend against it.
Regardless, it is possible using a builder and a proxy:
Assume the properties are asynchronously defined as follows:
var properties_to_append = {
load : function(path){
return this.then((view_loader)=>{ console.log("loading " + path); return view_loader.load(path)}) // define `view_loader.load()` to the view_loader promise
},
generate : function(options){
return this.then((compiler)=>{ return compiler.generate(options) })
},
}
var promise_properties = Promise.resolve(properties_to_append);
Then utilizing the AsyncPropertyPromise
class defined further down the following works as expected:
var async_property_promise = new AsyncPropertyPromise(require("clientside-view-loader"), promise_properties);
async_property_promise // works
.load("clientside-view-modal-login_signup") // works
.generate() // works
.then((modal)=>{
document.body.appendChild(modal);
modal.show("login");
})
AsyncPropertyPromise:
var unknown_properties_deferment_handler = {
return_defined_target_value : function(target, prop){
var value = target[prop];
var bound_value = typeof value == 'function' ? value.bind(target) : value; // bind functions to target, as they would expect
return bound_value; // return the requested name or parameters
},
get: function(target, prop) {
if(prop in target){
return this.return_defined_target_value(target, prop); // if the requested method or parameter is in the target object, just return it
} else {
return target.promise_to_attempt_to_get_async_property(prop);
}
}
};
class AsyncPropertyPromise {
constructor(original_promise, promise_properties) {
this.original_promise = original_promise;
this.promise_properties = promise_properties;
var proxied_self = new Proxy(this, unknown_properties_deferment_handler);
return proxied_self;
}
then(...args) {
return this.original_promise.then(...args);
}
catch(...args){
return this.original_promise.catch(...args);
}
promise_to_attempt_to_get_async_property(property){
/*
1. return a function - NOTE - this assumes that any property not statically defiend is a function
2. make that function resolve with an AsnycPropertyPromise that
a. returns the value of the property (method) if it exists
b. throws error if it does not
*/
return function(...args){ // 1
var raw_response_promise = this.promise_properties // 2
.then((loaded_properties)=>{
if(!(property in loaded_properties)) throw "property not defined"; // 2.a
var value = loaded_properties[property];
var bound_value = value.bind(this); // bind to original_promise
return bound_value(...args); // evaluate and return response while passing orig arguments; see `spread` https://stackoverflow.com/a/31035825/3068233
});
var async_proxied_response_promise = this._wrap_a_promise(raw_response_promise);
return async_proxied_response_promise;
}
}
_wrap_a_promise(raw_promise){
return new this.constructor(raw_promise, this.promise_properties);
}
}