如何异步添加属性到promise?

时间:2018-02-15 16:43:47

标签: javascript asynchronous promise

在这个问题中:How to add a custom property or method to a promise?有关于如何添加属性的简单解决方案"预先知道属性时 的承诺函数

对于clientside-require模块,我试图启用require()函数加载的包,将自己的属性附加到require()返回的承诺。例如,要启用此功能:

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");
    })

或者

var promies_request_package = require("clientside-request")
promies_request_package
    .request("https://google.com")
    .then((response)=>{
       console.log(response)
    })

问题是我们要求的每个软件包都应该能够定义自己的自定义属性。换句话说, 我们不知道同步属性 。首先,我们需要解析promise_module_properties,然后根据这些属性,必须修改require生成的承诺的属性。

这可能吗?

1 个答案:

答案 0 :(得分:-1)

正如Bergi所说,仅仅因为我们可以这样做并不意味着我们应该。事实上,我强烈建议反对它。

无论如何,可以使用builder和代理:

假设属性的异步定义如下:

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);

然后利用下面定义的AsyncPropertyPromise类,按预期工作:

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);
    }
}