如何实现使用GAS几秒后运行的触发器或计时器 [英] How to implement a trigger or timer that runs after a few seconds using GAS

查看:250
本文介绍了如何实现使用GAS几秒后运行的触发器或计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在加载时,如果在 doGet()中使用UIapp(=之后的返回应用程序; ),但在使用之前执行鼠标或键盘动作)我有2个耗时的任务运行。
第一项任务需要15到30秒,第二项任务通常需要40到60秒。



同时,我希望用户看到用户界面,并能够输入一些数据在文本框等。
所以我想使用空闲时间并使用短时间间隔(几秒钟)执行第一个任务。这样,用户应该能够执行不需要任务2的工作,而不会有太多延迟。



完成第一个任务后,我想要启动task-2一个更大的时间间隔(10-15秒左右)。



阅读 https://developers.google.com/apps-script/reference/script/clock-trigger-builder ,我注意到关于触发器运行的几点评论在15分钟内。这对我没有用处。尽管如此,我试图实现这个(见代码),但事实证明,代码只运行一次,偶尔触发器会在一分钟左右内第二次运行。

  var globalUsedMimeTypes ='globalUsedMimeTypes'; 

函数getUsedMimeTypes()
{//调查现有文件的所有mime类型
//因为这可能耗时(对于800个文件超过10秒),将使用空闲时间,除非需要搜索
var Logger = BetterLog.useSpreadsheet('1NYQZqG2z4_2r96L9EFvkbrJJFeb3v3sapPVXjo-Elfo','Tree');
Logger.log('getUsedMimeTypes');
var startTime = Date.now();

deleteTriggerByHandler('getUsedMimeTypes'); //删除触发器(如果有)

var delimiter =';';
var maxSeconds = 2; //处理每个批次所允许的最大时间
var waitSeconds = 5; //计算恢复之前的等待时间

var currentMimeTypes ='';

var userProperties = PropertiesService.getUserProperties();
var continuationToken = userProperties.getProperty('getUsedMimeTypes');
if(continuationToken == null)
{//开始新的调查
Logger.log('continuationToken == null');
var files = DriveApp.getFiles();
var continuationToken = files.getContinuationToken();
userProperties.setProperty('getUsedMimeTypes',continuationToken);
userProperties.setProperty(globalUsedMimeTypes,currentMimeTypes);
}
else
{//从执行被中断的地方继续
var files = DriveApp.continueFileIterator(continuationToken);
var currentMimeTypes = userProperties.getProperty(globalUsedMimeTypes);
Logger.log('continuation currentMimeTypes ='+ currentMimeTypes);
}
var mimeTypes = currentMimeTypes.split(delimiter);
var arrMimeTypes = [];
var numMimeTypes = mimeTypes.length; (var i = 0; i< numMimeTypes; i ++)arrMimeTypes [mimeTypes [i]] = 0;
//未定义'

var maxTime = maxSeconds * 1000; //每批允许的毫秒数 - >现在没有测试(因为numFiles会及时停止)
var numFiles = 75; //((!!= numFiles--)&& files.hasNext())
{
var file = files在一次检查的文件的最大数目
。下一个();
var mimeType = file.getMimeType();
if(arrMimeTypes [mimeType] == undefined)
{//找到一个新的mimeType
Logger.log('found new mimeType ='+ mimeType);
arrMimeTypes [mimeType] = 0;
currentMimeTypes = mimeType +分隔符+ currentMimeTypes;
numMimeTypes ++;
}
}

continuationToken = files.getContinuationToken();
if(continuationToken == null)
{//完成处理
currentMimeTypes = currentMimeTypes.substr(0,currentMimeTypes.length - delimiter.length); //删除分隔符
userProperties.deleteProperty('getUsedMimeTypes');
}
else
{//继续处理
Logger.log('create new trigger currentMimeTypes ='+ currentMimeTypes);
userProperties.setProperty('getUsedMimeTypes',continuationToken);
ScriptApp.newTrigger('getUsedMimeTypes')。timeBased()。after(waitSeconds * 1000).create();
}

userProperties.setProperty(globalUsedMimeTypes,currentMimeTypes); //存储调查过的mimeTypes(包括处理

var endTime = Date.now();
时的分隔符)'Logger.log('numMimeTypes ='+ numMimeTypes +'runtime ='+((endTime -startTime)/ 1000)+'seconds'+'finished ='+(continuationToken == null));

返回arrMimeTypes;
}

函数deleteTriggerByHandler (nameHandler)
{//根据函数的名称删除触发器
var deleted = false;

var allTriggers = ScriptApp.getProjectTriggers();

var numTriggers = allTriggers.length;
for(var i = 0; i< numTriggers; i ++)
{
if(allTriggers [i] .getHandlerFunction() == nameHandler)
{//找到我们要查找的触发器
ScriptApp.deleteTrigger(allTriggers [i]);
deleted = true;
break;
}
}
返回已删除;
}

我的问题是:

<1>有可能为我打算做的事情使用触发器吗?如果不是的话:我能做些什么来实现我的目标?

2)触发器实际上是否有一段时间来触发?如果是这样,它是多少,为什么?
$ b $ 3这是我第一次使用触发器:我的代码是否正确?



4)我应该使用空闲时间(由MouseMove和KeyPress检测)吗?如果是这样,我应该为整个面板创建一个achor,还是可以直接使用面板?



输出示例:

  2014-06-11 23:38:23:273 +0200 049502 INFO生成memoryTree需要48.586秒
2014-06-11 23:38:23 :553 +0200 049782 INFO getUsedMimeTypes
2014-06-11 23:38:24:094 +0200 050323信息continuationToken == null
2014-06-11 23:38:25:448 +0200 051678 INFO找到新的mimeType = application / vnd.google-apps.spreadsheet
2014-06-11 23:38:25:451 +0200 051680 INFO found new mimeType = application / vnd.google-apps.document
2014-06-11 23:38:25:455 +0200 051684 INFO found found mimeType = application / vnd.google-apps.script
2014-06-11 23:38:25:459 +0200 051688 INFO找到新的mimeType = application / pdf
2014-06-11 23:38:25:499 +0200 051728 INFO创建新触发器currentMimeTypes = application / pdf; application / vnd.google-apps.script; application / vnd。谷歌-apps.document;应用/ vnd.google-apps.spreadsheet;
2014-06-11 23:38:26:018 +0200 052247 INFO numMimeTypes = 1 runtime = 2.464 seconds finished = false
2014-06-11 23:38:26:021 +0200 052250 INFO onLoadPageTwoHandler
2014-06-11 23:38:26:023 +0200 052252 INFO onLoadHandlerPageThree
2014-06-11 23:38:42:564 +0200 000875 INFO getUsedMimeTypes
2014-06 -11 23:38:43:029 +0200 001340 INFO continuation currentMimeTypes = application / pdf; application / vnd.google-apps.script; application / vnd.google-apps.document; application / vnd.google-apps.spreadsheet;
2014-06-11 23:38:43:932 +0200 002244 INFO found found mimeType = image / jpeg
2014-06-11 23:38:43:950 +0200 002261 INFO found new mimeType = video / mp4
2014-06-11 23:38:45:039 +0200 003350 INFO发现新的mimeType = application / vnd.ms-excel
2014-06-11 23:38:45: 044 +0200 003355 INFO found found mimeType = application / msword
2014-06-11 23:38:45:070 +0200 003381 INFO found new mimeType = application / vnd.ms-powerpoint
2014-06 -11 23:38:45:076 +0200 003387 INFO创建新触发器currentMimeTypes = application / vnd.ms-powerpoint; application / msword; application / vnd.ms-excel; video / mp4; image / jpeg; application / pdf;应用/ vnd.google-apps.script;应用/ vnd.google-apps.document;应用/ vnd.google-apps.spreadsheet;
2014-06-11 23:38:45:417 +0200 003728 INFO numMimeTypes = 9 runtime = 2.849 seconds finished = false

之后没有输出

解决方案

我使用addTimer解决了我的问题。
这允许将任务分成几部分。



虽然没有经过测试,但甚至可能以这种方式克服5分钟限制。

 函数doget()
{
<常见代码>

var handler = app.createServerHandler('startTask');
app.addTimer(handler,3000); //允许UI加载并在之后启动任务

return app;


函数startTask(e)
{//执行响应式UI需要很多时间的几项任务的第1部分

var handler = app.createServerHandler('partTwo');
app.addTimer(handler,1500); //允许UI响应

return app;
}

函数partTwo(e)
{//执行响应式UI需要太多时间的几个任务的第2部分
<第2部分;可以使用continuationToken>

返回应用;
}


At loadtime if the UIapp (= after return app; in doGet() , but before the use can perform mouse or keyboardactions) I have 2 timeconsuming tasks to run. The first task will take 15 to 30 seconds, the second usually takes between 40 and 60 seconds.

In the mean time I want the user to see the UI and be able to enter some data in textboxes and so. So I would like to use idle time and execute the first task using short timeintervals (a few seconds) . This way the user should be able to perform work not requiring task-2 to finish without much delay.

After the first tasks finishes, I want to start task-2 with a somewhat larger timeinterval (10-15 seconds or so).

Reading https://developers.google.com/apps-script/reference/script/clock-trigger-builder , I noticed several remarks about a trigger running within 15 minutes. That's of no use to me. Nevertheless I tried to implement this (see code), but it turns out the code runs once and OCCASIONALLY the trigger runs a second time within a minute or so.

var globalUsedMimeTypes = 'globalUsedMimeTypes';

function getUsedMimeTypes()
{ // Investigate all mimeTypes of existing files
  // As this can be timeconsuming (over 10 seconds for 800 files), this will be done using idle time unless required for searching  
   var Logger = BetterLog.useSpreadsheet('1NYQZqG2z4_2r96L9EFvkbrJJFeb3v3sapPVXjo-Elfo', 'Tree');
   Logger.log('getUsedMimeTypes');  
   var startTime = Date.now();

   deleteTriggerByHandler('getUsedMimeTypes');       // Remove the trigger (if any)

   var delimiter   = ';';
   var maxSeconds  = 2;   // Maximum time allowed for processing each batch
   var waitSeconds = 5;   // Time to wait before the calculation will be resumed

   var currentMimeTypes = '';

   var userProperties = PropertiesService.getUserProperties();
   var continuationToken = userProperties.getProperty('getUsedMimeTypes');
   if (continuationToken == null)
   { // Start new investigation
   Logger.log('continuationToken==null');     
      var files = DriveApp.getFiles();
      var continuationToken = files.getContinuationToken();
      userProperties.setProperty('getUsedMimeTypes', continuationToken);
      userProperties.setProperty(globalUsedMimeTypes, currentMimeTypes);
   }
   else 
   { // Continue from where execution has been interrupted
      var files = DriveApp.continueFileIterator(continuationToken);
      var currentMimeTypes = userProperties.getProperty(globalUsedMimeTypes);
Logger.log('continuation   currentMimeTypes= ' + currentMimeTypes);
   }
   var mimeTypes = currentMimeTypes.split(delimiter);
   var arrMimeTypes = [];
   var numMimeTypes = mimeTypes.length;
   for (var i=0; i<numMimeTypes; i++) arrMimeTypes[mimeTypes[i]] = 0; // Just not 'undefined'

   var maxTime  = maxSeconds * 1000; // Milliseconds allowed per batch --> not tested for now (as numFiles will stop in time)
   var numFiles = 75;                // Maximum number of files to be investigated at a time  
   while ((0 != numFiles--) && files.hasNext())
   {
      var file = files.next();
      var mimeType = file.getMimeType();
      if (arrMimeTypes[mimeType] == undefined)
      { // A new mimeType has been found
Logger.log('found new mimeType = ' + mimeType);
        arrMimeTypes[mimeType] = 0;
        currentMimeTypes = mimeType + delimiter + currentMimeTypes;
        numMimeTypes++;
      }
   }

   continuationToken = files.getContinuationToken();
   if (continuationToken == null)
   { // Finished processing
      currentMimeTypes = currentMimeTypes.substr(0, currentMimeTypes.length - delimiter.length); // Remove delimiter at the end
      userProperties.deleteProperty('getUsedMimeTypes');
   }  
   else
   { // Continue processing  
Logger.log('create new trigger  currentMimeTypes= ' + currentMimeTypes);     
      userProperties.setProperty('getUsedMimeTypes', continuationToken);
      ScriptApp.newTrigger('getUsedMimeTypes').timeBased().after(waitSeconds * 1000).create();
   }  

   userProperties.setProperty(globalUsedMimeTypes, currentMimeTypes); // Store investigated mimeTypes (including delimiter while processing

   var endTime = Date.now();  
   Logger.log('numMimeTypes= ' + numMimeTypes + '   runtime= ' + ((endTime-startTime) / 1000) + ' seconds' + '   finished= ' + (continuationToken == null));  

   return arrMimeTypes;
}  

function deleteTriggerByHandler(nameHandler)
{ // Delete a trigger based on the name of the function it excecutes
   var deleted = false;

   var allTriggers = ScriptApp.getProjectTriggers();

   var numTriggers = allTriggers.length;
   for (var i=0; i < numTriggers; i++)
   {
      if (allTriggers[i].getHandlerFunction() == nameHandler)
      { // Found the trigger we're looking for
         ScriptApp.deleteTrigger(allTriggers[i]);
         deleted = true;
         break;
      }
   }
   return deleted;
}

My questions are:

1) Is it possible to use a trigger for what I intend to do? If not : what can I do to achieve my goal?

2) Do triggers actually have a time period for firing? If so, how much is it and why?

3) As this is the first time I (want to) use a trigger : is my code correct?

4) Should I use idle time (detection by MouseMove and KeyPress)? If so, should I create an achor for the entire panel, or can I use a panel directly?

An example of output:

2014-06-11 23:38:23:273 +0200 049502 INFO Generate memoryTree takes 48.586 seconds
2014-06-11 23:38:23:553 +0200 049782 INFO getUsedMimeTypes
2014-06-11 23:38:24:094 +0200 050323 INFO continuationToken==null
2014-06-11 23:38:25:448 +0200 051678 INFO found new mimeType = application/vnd.google-apps.spreadsheet
2014-06-11 23:38:25:451 +0200 051680 INFO found new mimeType = application/vnd.google-apps.document
2014-06-11 23:38:25:455 +0200 051684 INFO found new mimeType = application/vnd.google-apps.script
2014-06-11 23:38:25:459 +0200 051688 INFO found new mimeType = application/pdf
2014-06-11 23:38:25:499 +0200 051728 INFO create new trigger  currentMimeTypes= application/pdf;application/vnd.google-apps.script;application/vnd.google-apps.document;application/vnd.google-apps.spreadsheet;
2014-06-11 23:38:26:018 +0200 052247 INFO numMimeTypes= 1   runtime= 2.464 seconds   finished= false
2014-06-11 23:38:26:021 +0200 052250 INFO onLoadPageTwoHandler
2014-06-11 23:38:26:023 +0200 052252 INFO onLoadHandlerPageThree
2014-06-11 23:38:42:564 +0200 000875 INFO getUsedMimeTypes
2014-06-11 23:38:43:029 +0200 001340 INFO continuation   currentMimeTypes= application/pdf;application/vnd.google-apps.script;application/vnd.google-apps.document;application/vnd.google-apps.spreadsheet;
2014-06-11 23:38:43:932 +0200 002244 INFO found new mimeType = image/jpeg
2014-06-11 23:38:43:950 +0200 002261 INFO found new mimeType = video/mp4
2014-06-11 23:38:45:039 +0200 003350 INFO found new mimeType = application/vnd.ms-excel
2014-06-11 23:38:45:044 +0200 003355 INFO found new mimeType = application/msword
2014-06-11 23:38:45:070 +0200 003381 INFO found new mimeType = application/vnd.ms-powerpoint
2014-06-11 23:38:45:076 +0200 003387 INFO create new trigger  currentMimeTypes= application/vnd.ms-powerpoint;application/msword;application/vnd.ms-excel;video/mp4;image/jpeg;application/pdf;application/vnd.google-apps.script;application/vnd.google-apps.document;application/vnd.google-apps.spreadsheet;
2014-06-11 23:38:45:417 +0200 003728 INFO numMimeTypes= 9   runtime= 2.849 seconds   finished= false

afterwards no output

解决方案

I solved my problem using addTimer. This allows to split tasks into parts.

Allthough not tested it might even be possible to overcome the 5 minutes limit this way.

function doget()
{
   <usual code>

   var handler = app.createServerHandler('startTask');
   app.addTimer(handler, 3000); // Allow the UI to load and start the tasks afterwards

   return app;
}

function startTask(e)
{ // Perform part 1 of several tasks that take too much time for a responsive UI
   <some actions>

   var handler = app.createServerHandler('partTwo');
   app.addTimer(handler, 1500); // Allow the UI to respond

   return app;
}

function partTwo(e)
{ // Perform part 2 of several tasks that take too much time for a responsive UI
   <actions of part Two ; a continuationToken might be used>

   return app;
}

这篇关于如何实现使用GAS几秒后运行的触发器或计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆