0

经常 GAS 用户(我也是)不使用ServerHandler.addCallbackElement方法或以不涵盖所有控件的方式使用。

有这种方法的背景是什么?为什么 GAS 开发者要引入它?将所有输入小部件值作为参数传递给所有服务器处理程序是否更简单?

文档没有提供这些问题的答案。

我看到以下原因

  1. 在处理不同控件集的多个处理程序的情况下,添加小部件作为回调元素可以减少浏览器和 GAS 服务器之间的流量。这是一个问题。它节省了多少流量?我认为最多几千字节,通常是数百字节。考虑到现代互联网连接速度,甚至移动连接,是否值得。
  2. 表单包含带有多个按钮的类似表格的编辑控件,并且可以轻松处理具有相同名称的行元素。这个问题很容易通过使用来避免tags。请参阅以下示例。如果标签用于其他目的,解析源按钮 id 并提取行号不是问题。
  3. 幕后使用的技术限制。如果有这样的限制,那么它们是什么?
function doGet(e) {
  var app = UiApp.createApplication();
  var vPanel = app.createVerticalPanel();
  var handler = app.createServerHandler("onBtnClick");
  var lstWidgets = [];
  for (var i = 0; i < 10; i++) {
    var hPanel = app.createHorizontalPanel().setTag('id_' + i);
    var text = app.createTextBox().setName("text_" + i);
    text.setText(new Date().valueOf());
    var btn = app.createButton("click me").addClickHandler(handler);
    btn.setTag(i).setId('id_btn' + i);
    var lbl = app.createLabel().setId("lbl_" + i);
    hPanel.add(text);
    hPanel.add(btn);
    hPanel.add(lbl);
    lstWidgets.push(text);
    lstWidgets.push(btn);
    vPanel.add(hPanel);
  }
  // The addCallbackElement calls simulate situation when all widgets values are passed to a single server handler.
  for (var j = 0; j < lstWidgets.length; j++) {
    handler.addCallbackElement(lstWidgets[j]); 
  }
  app.add(vPanel);
  return app;
}

function onBtnClick(e) {
  var app = UiApp.getActiveApplication();
  var i = e.parameter[e.parameter.source + '_tag'];
  var lbl = app.getElementById("lbl_" + i);
  lbl.setText("Source ButtonID: " + e.parameter.source + ', Text: ' + e.parameter["text_" + i]);
  return app;
}
4

2 回答 2

3

好问题。

“它节省了多少流量?” 我想我们还不知道,但我希望随着时间的推移它会变得更有效率。这是关于性能的另一个讨论。只有来自 Google 的广泛测试和改进才能真正让我们确定最佳实践,目前我只能说 ClientHandlers 显然会尽可能地优于 ServerHandlers。

作为 JavaScript 开发人员,我认为我们主要习惯于在客户端做事,然后我们将 PHP/ASP 视为服务器端工具。到目前为止,我的理解是,我们的 GAS 代码实际上同时在客户端和服务器端运行(至少它正在调用服务器端功能),但似乎服务器端发生的事情比我们意识到的要多,而且在客户端这似乎导致了一些“编译”的代码。从我的 Java 经验中,我有点认识到这种多层部署。

由于有很多方法可以做同样的事情,谷歌可以利用我们的代码不是直接解释(由任何一方)的事实来做如果我们手工编写代码不一定有意义的事情。这就是为什么我认为它最终会比其他解决方案更有效,但可能还没有。现在,如果您担心性能,我建议您避开 GAS。也许只是为了好玩尝试在运行时查看客户端 Web 应用程序的源代码(查看源代码)。因此,为了让他们最有效地做事,我想他们会因为让我们以非常高层次的方式定义事物而受益。这使他们在解释我们的代码方面具有最大的灵活性。

为了具体解决您的第二个问题,我个人认为处理函数 onBtnClick() 在服务器端运行,而您引用的标签(以及大多数 doGet)将在客户端的浏览器引擎中。如果他们提前知道处理特定事件/请求需要多少内存,我可以看到该功能在服务器端将如何更加灵活(高效和强大)。(很明显,如果每个 getElementById() 调用都运行一个单独的请求,那就像每次单击一个指向新迷你网页的链接一样。)

所以现在的问题是为什么我的处理程序不能只使用我在处理程序函数中使用的东西自动创建参数?我们首先提出这个问题的唯一原因是因为 UiApp 中有一些东西似乎在两端都可用。UiApp 已经在 doGet 和 onClick 的范围内,但 doGet 中定义的变量不在,因此这些值需要是

  • 像 ScriptProperties.setProperty() 或
  • 将 UiApp 放入带有 Id 的某处或
  • 使用 addCallbackElement() 显式赋予 Handler 函数

请注意您必须如何添加CallbackElement(lstWidget),因为它不是使用 UiApp 对象中的 app.create... 构造函数创建的。我的猜测是 GAS 正在对 Google 端的 Web 服务实现符合 XML 的 SOAP 调用,我们可以通过真正研究客户端源代码来解决这个问题。重申一下,我们也可以使用 setProperty() 这并不重要,甚至可以通过 JDBC 保存它们,然后从您的处理程序函数中使用另一个连接检索它们,但不知何故,数据需要从客户端传递到服务器,反之亦然-反之亦然。

从编程的角度来看,您的客户端 doGet 函数范围内有很多可用的东西,您可能永远不想传递给服务器,或者服务器端 doClick() 范围内可能有函数与客户端上的函数同名,但它们实际上可能是对完全不同的库函数的调用,甚至可能在完全不同的硬件上(即使从开发人员的角度来看它们的工作方式相同)。

也许谷歌团队还没有真正决定 UiApp 的真正运作方式,否则他们只会强制或至少允许我们把所有东西放在那里。当我们根据它的名称调用 UiApp.getActiveApplication() 时,另一个观察结果看起来不像是构造函数,而是从 UiApp 对象返回私有实例的方法。(对象是一个先前已实例化并假定在某处初始化的类。)我可能没有 100% 回答您的问题,但我确实尝试过,社区的任何进一步见解显然将不胜感激。

现在我可能跑题了,但我也想象实际产品会继续改变,因为他们会做更多的事情来提高长期性能,如果我们仍然觉得我们正在作为开发人员编写客户端代码,那么对谷歌来说是成功的。现在,如果我说错了,请纠正我,我最近才开始使用这些工具,并计划随着我了解的更多细节来跟进这个问题,但到目前为止,这是我最好的解释。

于 2012-12-01T20:51:59.057 回答
0

如果您使用表单面板,所有子元素都将发送到您的 dopost 函数。以按钮为源。你的 UIapp 将被清理。

如果您不希望使用回调来指定将发送的元素和兄弟姐妹。

这就是 UIapp 的设计方式。

于 2012-10-12T19:38:38.443 回答