在这个(我承认不是很多......)有趣的问题背后是一个关于我使用的解决方法的真正问题,但我并没有真正理解它是如何工作的。
首先简要描述一下我的用例,所有这些都发生在侧边栏中显示的文档绑定 UiApp 中:
我必须在用 GAS 编写的邮件合并应用程序中创建并通过电子邮件发送数百个文档。在不达到 5 分钟执行时间限制的情况下,一批处理当然需要很长时间,所以我尝试了几种不同的解决方法来完成任务:
- 当我开始进程时使用时间戳(存储在 ScriptProperties 中),当我达到接近限制的预定义值时,我存储当前值(指针、有用的变量......)并返回到用户界面,要求用户继续(或不)。这工作得很好,但需要一个人的行动来完成整个任务。
- 因此,我使用在第一个处理程序调用中创建的计时器触发器设置了一个解决方案,该触发器调用了文档创建/发送函数。这也很好用,但调用函数的触发器无法与 UI 交互,因为似乎只有处理函数可以更新 UI。问题是我无法显示进度,也无法轻松显示进程何时结束。
- 然后我想起了一个前段时间写的一个小应用程序,只是为了好玩:它是一个使用复选框作为服务器处理程序触发器的计时器(来自 Romain Vialard 很久以前在旧谷歌论坛上提出的一个想法)并决定试试这个我的邮件发送过程中的技巧。
它工作得很好,我处理 40 个文档批次是每个调用(大约 3 分钟)然后暂停一段时间,然后重新开始,直到它完成。每个调用都由 checkBox 链接服务器处理程序触发,复选框本身在处理程序函数中发生更改,以这种方式创建自己的触发器。
我的问题(最后;-)是:知道整个过程可能需要 30 到 60 分钟,这有多精确? 这些服务器处理程序函数如何/为什么被视为多个进程,因为它们是从函数本身内部创建的?
我希望我足够清楚,(我对此表示怀疑,因为这在我看来有点混乱:-)
我加入了给我这个想法的时钟测试应用程序的代码,它可能会让事情更容易理解。
function doGet() {
var app = UiApp.createApplication().setTitle('Counter/Timer');
var Panel = app.createAbsolutePanel().setStyleAttribute('padding','35');
var counter = app.createHTML().setId('counter').setHTML('<B>Timer = wait</B>').setStyleAttribute('fontSize','40px');// set start display
var clo = app.createTextBox().setName('clo').setId('clo').setValue('0').setVisible(false);//set start value in seconds
var handler1 = app.createServerHandler('doSomething').addCallbackElement(Panel);
var chk1 = app.createCheckBox('test1').addValueChangeHandler(handler1).setVisible(true).setId('chk1').setVisible(false);
app.add(Panel.add(chk1).add(counter).add(clo));
chk1.setValue(true,true);// start the process
return app}
function doSomething(e) {
var app = UiApp.getActiveApplication();
var xx = Number(e.parameter.clo);
var disp = app.getElementById('counter')
xx++ ;// replace by xx-- to count downwards
if(xx>600){ // 10 minutes timeout for example
disp.setHTML('<B> GAME OVER ;-)</B>').setStyleAttribute('fontSize','80px').setStyleAttribute('color','RED')
return app
}
var cnt = app.getElementById('clo').setValue(xx)
disp.setHTML('<B>'+T(xx)+'</B>')
Utilities.sleep(1000); // instead of sleeping do something !
// below comes the "active" part
var chk1 = app.getElementById('chk1').setValue(false,false)
var chk1 = app.getElementById('chk1').setValue(true,true)
return app;
}
function T(val){
var min = parseInt(val/60);
var sec = val-(60*min);
if(sec<10){sec='0'+sec}
if(min<10){min='0'+min}
var st = '> '+min+':'+sec
return st
}