与超时保护环,仅运行一次“因为它应该”(Loop with timeout protection t

2019-09-03 03:52发布

我写了从用电子表格中的备份恢复日历数据的脚本。 由于数据量是非常难以预测的,我设计一个回路分钟的指定次数后,即停止,让用户continuecancel ,同时显示实际计数器状态(此为防止与谷歌最大执行时间限制的问题)。

它工作得很好,但在这个简单的测试脚本我用来测试它的作品只有一次的想法:当第一个“超时”的发生,它显示了continue/cancel的预期选项,然后从那里开始,但继续在相同的条件下发生第二次continue按钮不会显示出来。

我的问题很简单:为什么呢? 或者更好的是什么这两种情况之间的区别?

与嵌入脚本的电子表格是这里公开检验的 (见menu : test

而整个脚本如下所示(这是一个有点长,当然,但interresting部分已经接近尾声)

我用ScriptProperties跟踪的执行时间,并继续从我离开那里,循环。

function onOpen() {   
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
                     {name: "test", functionName: "test"},  
                      ];  
  ss.addMenu("test", menuEntries);  
}

function test(){
  ScriptProperties.setProperty('restorePointers',[0,0].join('@'))
  var app = UiApp.createApplication().setTitle("test");
  app.setHeight(150).setWidth(250);
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var panel = app.createVerticalPanel();
  var handlerCancel = app.createServerHandler('canceltest');
  var handlerContinue = app.createServerHandler('continuetest');
  var contCHandler = app.createClientHandler();
  var cancel = app.createButton("cancel.", handlerCancel).setId('cancel').setVisible(false);
  var cont = app.createButton('continue',handlerContinue).setId('continue').setVisible(false).addClickHandler(contCHandler);
  var button = app.createButton('start').setId('button');
  var handler = app.createServerClickHandler('runtest');
  handler.addCallbackElement(panel);
  contCHandler.forTargets(button).setEnabled(false).forEventSource().setVisible(false);
  var cHandler = app.createClientHandler().forTargets(cancel).setVisible(true).forEventSource().setVisible(false);
  button.addClickHandler(handler).addClickHandler(cHandler);
  app.add(panel.add(button).add(cont).add(cancel))//.add(trig));
  doc.show(app);
}

function canceltest(e){
  var app = UiApp.getActiveApplication();
   ScriptProperties.setProperty('restoreData','')
   ScriptProperties.setProperty('restorePointers','canceled');
   SpreadsheetApp.getActiveSpreadsheet().toast('  ','restore aborted');
   app.close()
   return app;  
}  

function continuetest(e){
  runtest(e)
  }

function runtest(e){
  var dStart; var dEnd;
  ScriptProperties.setProperty('startrestore',new Date().getTime().toString())
    if(ScriptProperties.getProperty('restoreData')==null||Utilities.jsonStringify(ScriptProperties.getProperties()).indexOf('restoreData')==-1)
      {ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e))
      }
  var app = UiApp.getActiveApplication();
  var pointers = ScriptProperties.getProperty('restorePointers');
   if(pointers=='0@0'){
   dStart = 0;
   dEnd = 500;
   }else{
   dStart = Number(pointers.split('@')[0]);
   dEnd = Number(pointers.split('@')[1]);
   }
// main loop --------------------------
      for(var ee=dStart;ee<dEnd;++ee){ // main loop
           var ccc = ScriptProperties.getProperty('restorePointers');
           if(ccc=='canceled'){ app.close();return app};

      Utilities.sleep(85); // simulate some activity


   if((ee/10)==parseInt(ee/10)&&ee>0){
     SpreadsheetApp.getActiveSpreadsheet().toast(ee+' steps completed')
       if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>12000){ ;//  +- 12 sec timeout
           ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@'));
           app.getElementById('continue').setHTML('continue from '+ee).setVisible(true)
           return app
           }
        }
    }
// end of main loop-----------------  
   ScriptProperties.setProperty('restoreData','')
   ScriptProperties.setProperty('restorePointers',0+'@'+0);
   SpreadsheetApp.getActiveSpreadsheet().toast('normal process end');
   app.close();
   return app;  
} 

Answer 1:

这里是什么保持“继续”按钮,从每个间隔更新。 您的服务器处理器需要返回一个应用程序:

function continuetest(e){
  return runtest(e)  ///<<<
}

该位, (ee/10)==parseInt(ee/10)是评价一个尴尬的方式true每第10个项目。 使用模数来代替:

if((ee%10==0)&&ee>0){ ///<<< modulus

每次暂停后,EE的值被重复在烤面包。 这可以通过记住什么最后显示的值,并跳过它是固定的。

if (ee == Number(ScriptProperties.getProperty('lastToast'))) continue; ///<<< don't repeat toast
ScriptProperties.setProperty('lastToast',ee);  ///<<<

完整的脚本

function onOpen() {   
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
                     {name: "test", functionName: "test"},  
                      ];  
  ss.addMenu("test", menuEntries);  
}

function test(){
  ScriptProperties.setProperty('restorePointers',[0,0].join('@'))
  var app = UiApp.createApplication().setTitle("test");
  app.setHeight(150).setWidth(250);
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var panel = app.createVerticalPanel();
  var handlerCancel = app.createServerHandler('canceltest');
  var handlerContinue = app.createServerHandler('continuetest');
  var contCHandler = app.createClientHandler();
  var cancel = app.createButton("cancel.", handlerCancel).setId('cancel').setVisible(false);
  var cont = app.createButton('continue',handlerContinue).setId('continue').setVisible(false).addClickHandler(contCHandler);
  var start = app.createButton('start').setId('start');
  var handler = app.createServerClickHandler('runtest');
  handler.addCallbackElement(panel);
  contCHandler.forTargets(start).setEnabled(false).forEventSource().setVisible(false);
  var cHandler = app.createClientHandler().forTargets(cancel).setVisible(true).forEventSource().setVisible(false);
  start.addClickHandler(handler).addClickHandler(cHandler);
  app.add(panel.add(start).add(cont).add(cancel))//.add(trig));
  doc.show(app);
}

function canceltest(e){
  var app = UiApp.getActiveApplication();
   ScriptProperties.setProperty('restoreData','')
   ScriptProperties.setProperty('restorePointers','canceled');
   SpreadsheetApp.getActiveSpreadsheet().toast('  ','restore aborted');
   app.close()
   return app;  
}  

function continuetest(e){
  return runtest(e)  ///<<<
  }

function runtest(e){
  var dStart; var dEnd;
  ScriptProperties.setProperty('startrestore',new Date().getTime().toString())
    if(ScriptProperties.getProperty('restoreData')==null||Utilities.jsonStringify(ScriptProperties.getProperties()).indexOf('restoreData')==-1)
      {ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e))
      }
  var app = UiApp.getActiveApplication();
  var pointers = ScriptProperties.getProperty('restorePointers');
   if(pointers=='0@0'){
   dStart = 0;
   dEnd = 500;
   }else{
   dStart = Number(pointers.split('@')[0]);
   dEnd = Number(pointers.split('@')[1]);
   }
// main loop --------------------------
      for(var ee=dStart;ee<dEnd;++ee){ // main loop
           var ccc = ScriptProperties.getProperty('restorePointers');
           if(ccc=='canceled'){ app.close();return app};

      Utilities.sleep(85); // simulate some activity


   if((ee%10==0)&&ee>0){ ///<<< modulus
     if (ee == Number(ScriptProperties.getProperty('lastToast'))) continue; ///<<< don't repeat toast
     ScriptProperties.setProperty('lastToast',ee);  ///<<<
     SpreadsheetApp.getActiveSpreadsheet().toast(ee+' steps completed')
       if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>12000) { //  +- 12 sec timeout  
           ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@'));
           app.getElementById('continue').setHTML('continue from '+ee).setVisible(true)
           return app
           }
        }
    }
// end of main loop-----------------  
   ScriptProperties.setProperty('restoreData','')
   ScriptProperties.setProperty('restorePointers',0+'@'+0);
   SpreadsheetApp.getActiveSpreadsheet().toast('normal process end');
   app.close();
   return app;  
} 


文章来源: Loop with timeout protection that only runs once “as it should”