【问题标题】:Javascript smooth method chainingJavascript 平滑方法链接
【发布时间】:2012-05-15 21:02:48
【问题描述】:

我有一个可以接受某些参数的网络服务,例如 ?top=5&orderby=column --- 等等...

我希望能够像这样执行我的对象:

var call = new API();
call.get().top(5).skip(15).orderby("address");

挑战是只有最后一个 orderby 触发 execute() 方法。这是我的代码。如果您有更好的想法,请告诉我!当前每个函数结束时延迟 25ms,并在下一个函数开始时停止计时器。这是适当的/可以接受的吗?


var API = function (webservice) {
this.webservice(webservice);
return this;
};

API.prototype = {
version: function (urlFormat) {
    if (urlFormat) {
        return "v" + urlFormat.split('.').join('_');
    }
    return sessionStorage.getItem("version");
},
path: function () {
    return "../WebAPI/";
},
execute: function () {
    var path = this.path() + this.webservice() + ".svc/";
    if (this.__parameters) {
        path += "?";
    }
    var first = true;
    for (var k in this.__parameters) {
        if (k !== "type")
        path += ((first) ? (function(){first = false; return ""})() : "&") + "$" + k + "=" + this.__parameters[k];
    };
    console.log(this.__parameters.type + ": " + path);
    return this;
},
put: function () {
    this.doIt("type","put");
    return this;
},
post: function () {
    this.doIt("type","post");
    return this;
},
get: function() {
    this.doIt("type","get");
    return this;
},
delete: function() {
    this.doIt("type","delete");
    return this;
},
toString: function () {
    return "API";
},
webservice: function(webservice) {
    if (webservice) {
        this.__webservice = webservice;
    }
    else {
        return this.__webservice;
    }
},
top: function (p) {
    this.doIt("top",p);
    return this;
},
view: function (p) {
    this.doIt("view",p);
    return this;
},
orderby: function (p) {
    this.doIt("orderby",p);
    return this;
},
criteria: function (p) {
    this.doIt("criteria",p);
    return this;
},
skip: function (p) {
    this.doIt("skip",p);
    return this;
},
filter: function (p) {
    this.doIt("filter",p);
    return this;
},
doIt: function (method, parameter) {
    this.__timerStop();
    this.__parameters[method] = parameter;
    this.__timerStart();
},
__timerStop: function () {
    if (this.__timer) {
        clearTimeout(this.__timer);
    }
},
__timerStart: function (append) {
    var self = this;
    if (this.__timer) {
        this.__timerStop();
    }
    this.__timer = setTimeout(function() {
        console.log("executing.");
        console.log(JSON.stringify(self.__parameters));
        self.execute();
    }, 25);
},
__parameters: {}
};

【问题讨论】:

  • 我不喜欢神奇地执行的想法。要么在每个方法调用之后执行,要么程序员必须显式地执行调用。我以前从未见过这种延迟执行,这让我毛骨悚然。

标签: javascript methods chaining


【解决方案1】:

更新:你知道吗?我将在这个问题上软化我的立场(下面的原始答案)。鉴于 JavaScript 的单线程事件循环,在您的方法链“完成”之前,您传递给 setTimeout 的回调永远不会触发,您实际上应该没问题。 (事实上​​,这也意味着您应该安全地将0 传递给setTimeout 而不是25。)

我仍然认为你想出这个设计是疯了(如果这是多个开发人员会接触的代码,我会说你最好使用更简单的设计,以减少团队混乱的风险过度复杂);但如果你坚持走这条路,你其实不应该遇到任何奇怪的黑森虫。

但是,是的,我坚持我最初的建议,即明确要求 execute 调用。


哦,伙计。你是疯狂甚至考虑到这一点!我的意思是,我的一部分确实爱你(我是big fan of horrifying hacks);但事实是采用这种方法,虽然它可能最终会奏效,但如果/当它失控时会让你发疯。

我强烈反对它的主要原因是替代方案非常简单,更重要的是,实际上可靠:只需建立execute 是实际发送请求的方法,因此任何链式方法调用都必须以该方法结束:

call.get().top(5).skip(15).orderby("address").execute();

如果你真的爱上了这个基于计时器的想法,那么有件事告诉我你以前从未真正遭受过Heisenbug 的痛苦(或者,正如我最初猜想的那样,你只是疯了)。

【讨论】:

  • 最重要的是,execute 方法可以采用一个回调函数,该函数可以传递一个 results 对象,使用户更容易指定 what他们希望在查询完成后完成。
  • 对于什么是值得的,你可以将 setTimeout 减少到 1(不是 0 - 0 = 没有延迟,因此 2 个请求) - 因为 JS “即时”评估代码,因此 1ms 是检查是否另一个的延迟方法存在于链中。虽然我必须同意上面的评论者 - 有没有执行功能的原因?
  • @eithed:我认为你错了。请参阅此 jsFiddle:jsfiddle.net/m3dqs。可以看到即使0被传递给setTimeout,回调函数并没有同步执行;因此循环的每次迭代都会取消前一次。
  • @Dan Tao:漂亮!我已经使用超时很长时间了,因此我假设了我所写的内容。干杯!
  • 我爱你,谢谢你,是的——我疯了。
【解决方案2】:

有趣的想法。虽然,为什么不这样做呢:

call({ type: "get", top: 5, skip: 15, orderby: "address" });

然后通过循环遍历 call 实现中的对象来处理每个参数,然后发出服务请求。

for(var arg in args) {
    if(args.hasOwnProperty(arg) && args.propertyIsEnumerable(arg)) {
        // process argument
    }
}

这让事情变得简单。

【讨论】:

  • 一个明显的原因 - 执行 call.get().top() 可能会做与 call.top().get() 不同的事情 - 如果将所有属性作为一个对象传递,则无法区分行为,但必须对其进行编码。例如: Cow.Eat('grass').Poo()Cow.Poo().Eat('grass') 不同,在第一个示例中,Cow 是空的,在第二个示例中,它全是草。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多