【问题标题】:How to implement a trigger or timer that runs after a few seconds using GAS如何使用 GAS 实现几秒钟后运行的触发器或计时器
【发布时间】:2014-06-11 21:33:40
【问题描述】:

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

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

第一个任务完成后,我想以稍长的时间间隔(10-15 秒左右)开始任务 2。

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

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;
}

我的问题是:

1) 是否可以为我打算做的事情使用触发器?如果不是:我可以做些什么来实现我的目标?

2) 触发器真的有触发时间吗?如果有,多少钱,为什么?

3) 因为这是我(想)第一次使用触发器:我的代码正确吗?

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

输出示例:

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

之后没有输出

【问题讨论】:

  • 关于触发时间,据我所知(截至目前),基于时间的触发的最精细粒度是每分钟。
  • 在“加载时间”是什么?网络应用程序?解释得更好。
  • 'return app;'之后在“doGet()”中,UIapp 被加载。但是用户可以执行操作(例如单击或键入)需要时间:'loadtime'
  • 触发器根本不适合这个。改用 webApp 和 ajax 调用。
  • 你能给我举个小例子吗?

标签: triggers google-apps-script google-drive-api


【解决方案1】:

我使用 addTimer 解决了我的问题。 这允许将任务拆分为多个部分。

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

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;
}

【讨论】:

    【解决方案2】:

    触发器不在您的应用范围内执行,因此您需要使用以下解决方法: What happens when I "sleep" in GAS ? (execution time limit workaround)

    【讨论】:

    • 我之前尝试过,但这不是我想要的
    • 你能解释一下为什么它不是你要找的吗?了解其他测试用例会很有趣
    猜你喜欢
    • 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
    相关资源
    最近更新 更多