0

当时的情况是我想创建一个帮助类的实例,但是这个帮助类需要通过外部脚本进行初始化,所以它本质上是异步的。和

var obj = new myObj();

显然是呼吁

obj.myMethod();

将产生未定义的结果,因为 obj 将是空的或未定义的,直到外部脚本加载其方法和参数。

是的,可以重组事物以具有回调模式并在其中使用新对象,但是当我一直在使用具有许多动态对象的大型多样 API 时,它会变得既麻烦又尴尬。

我的问题是,有没有办法巧妙地解决这个问题?

4

1 回答 1

1

我想那里受过学术训练的程序员对这种方法有一个名字,但我把它放在这里以防它在某个地方写得不好。

我所做的是修改我的加载器类以使用占位符+队列系统来立即返回可行的对象。

这是组件。抱歉,混入了 jQuery 位,您可以轻松地将其设为纯 JS 脚本,但无论如何我已经加载了它,而且我很懒。

'Client' 发出此请求,其中 'caller' 是我的处理程序类:

var obj = caller.use('myObj',args);

在 Caller 中,我们有

Caller.prototype.use = function(objname,args) {
    var _this = this;
    var methods = ['method1','method2'];
    var id = someRandomString();
    this.myASyncLoader(objname,function(){
        var q = [];
        if (_this.objs[id].loadqueue) {
            q = _this.objs[id].loadqueue;
        }
        _this.objs[id] = new myRemotelyLoadedClass(args);
        //realise all our placeholder stuff is now gone, we kept the queue in 'q'
        _this.objs[id].isloaded = true;
        //once again, the jquery is unnecessary, sorry
        $.each(q,function(a,b){
            _this.objs[id][b['f']](b['a']);
        });       
    });
    _this.objs[id] = _this.createPlaceholderObj(methods,id);
    return _this.objs[id];
}

这个函数基本上启动加载器函数,然后加载所需类的新实例。但与此同时,它会立即返回一些东西,一个占位符对象,我们将使用所有远程加载对象的方法来加载它。在这个例子中,我们必须在一个数组中显式地声明它们,这有点麻烦但可以生存,尽管我相信你可以为你自己的目的想出更好的方法来做到这一点。

您会看到我们将临时对象和未来对象都保存在一个类全局数组“objs”中,并与一个随机键相关联。

这是 createPlaceholderObj 方法:

Caller.prototype.createPlaceholderObj = function(methods,id) {
var _this = this;
var n = {};
n.tempid = id;
n.isloaded = false;
$.each(methods,function(a,methodCalled){
        n[methodCalled] = function(){
        _this.queueCall(id,methodCalled,arguments);
    }
});
return n;
 }

在这里,我们只是用所需的方法加载新的 obj,同时存储 ID,这很重要。我们为新方法分配了第三个函数 queueCall,我们将调用的方法及其发送时的任何参数传递给该函数。这是那个方法:

Caller.prototype.queueCall = function(id,methodName,args) {
if (this.objs[id].isloaded == true) {
    this.objs[id][methodName](args);
} else {
    if (this.objs[id].loadqueue) {
        this.objs[id].loadqueue.push({'f':methodName,'a':args});    
    } else {
        var arr = [{'f':methodName,'a':args}];
        this.objs[id].loadqueue = arr;
    }
}
}

每次客户端脚本调用我们的新对象实例的方法时,都会调用此方法,无论其逻辑是否已实际加载。此处的 IF 语句检查是哪种情况(异步函数完成后,调用方方法中的 isloaded 设置为 true)。如果对象没有加载,methodName 和参数将作为占位符的属性添加到队列数组中。如果它被加载,那么我们可以简单地执行该方法。

回到调用者方法,最后一个无法解释的位是我们检查是否有队列的地方,如果有,则循环遍历它并执行存储的方法名称和参数。

就是这样!现在我可以这样做:

var obj = caller.use('myObj',args);
obj.someMethod('cool');
obj.anotherMethod('beans');

虽然在这些方法实际执行之前可能会有一点延迟,但它们会毫无怨言地运行!

不是太短的解决方案,但如果你在做一个大项目,你可以把它放在一个地方,它会带来很多好处。

我希望对这个问题进行一些跟进。例如,我想知道你们中的一些人如何使用延迟承诺模式来做到这一点?或者如果有其他方法?或者如果有人知道这种技术叫什么?非常感谢来自 JS 高手的输入。

于 2012-07-29T16:09:46.283 回答