【问题标题】:Adding lockservice and SpreadsheetApp.flush to a script (Google App Script / Google Sheets)将 lockservice 和 SpreadsheetApp.flush 添加到脚本(Google App Script / Google Sheets)
【发布时间】:2020-09-24 23:14:22
【问题描述】:

研究如何使脚本在 IMPORTXML 完成收集数据之前不继续,我发现此功能是最常用的指示之一:

function testWait(){
  var lock = LockService.getScriptLock(); lock.waitLock(300000); 
  SpreadsheetApp.flush(); lock.releaseLock();
}

原文出处:
https://stackoverflow.com/a/43444080/11462274

我想知道我应该在哪里添加它以及需要添加多少次,是否应该在电子表格中调用 IMPORTXML 函数的每一行脚本下方添加它,或者我是否应该只在脚本的开头或结尾。

如果可能,请给我看一个示例,说明我的脚本在修改后的样子。

我的脚本示例(它要大得多,但为了问题不大,我将只发布一部分):

function myFunction() {
  var ss = SpreadsheetApp.getActive();
  ss.getRange('Monster!A1').setFormula('=IMPORTXML(Gerais!R1,"//*[@class=\'header-label\']"');
  ss.getRange('Monster!A1:A').copyTo(ss.getRange('Page 2!A1:A'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
  ss.getRange('Monster!A1').clear({contentsOnly: true, skipFilteredRows: true});
  
  ss.getRange('Monster!B1').setFormula('=IMPORTXML(Gerais!R2,"//*[@class=\'header-label\']"');
  ss.getRange('Monster!B1:B').copyTo(ss.getRange('Page 2!B1:B'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
  ss.getRange('Monster!B1').clear({contentsOnly: true, skipFilteredRows: true});
  
  ss.getRange('Monster!C1').setFormula('=IMPORTXML(Gerais!R3,"//*[@class=\'header-label\']"');
  ss.getRange('Monster!C1:C').copyTo(ss.getRange('Page 2!C1:C'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
  ss.getRange('Monster!C1').clear({contentsOnly: true, skipFilteredRows: true});
}

【问题讨论】:

    标签: google-apps-script google-sheets google-sheets-formula


    【解决方案1】:

    对引用的答案存在误解,建议的代码不打算在一个函数中多次使用,其目的是避免在同一脚本再次执行时执行代码的某些部分正在运行。


    以下代码减少了对 Google Apps 脚本方法的调用次数,包括使用 Spreadsheet.flush() 和一个 do...while 语句来等待电子表格重新计算鱼腥味。

    注意:由于未提供 URL,我没有对此进行测试。

    function myFunction() {
      var ss = SpreadsheetApp.getActive();
    
      // Add formulas
    
      ss.getRange('Monster!A1').setFormula('=IMPORTXML(Gerais!R1,"//*[@class=\'header-label\']"');
      ss.getRange('Monster!B1').setFormula('=IMPORTXML(Gerais!R2,"//*[@class=\'header-label\']"');
      ss.getRange('Monster!C1').setFormula('=IMPORTXML(Gerais!R3,"//*[@class=\'header-label\']"');
    
      // Force apply the above changes 
    
      SpreadsheetApp.flush();
    
      // Give time for spreadsheet recalculation
      var start = Date.now();
      var limit = 10000;
      do{
        Utilities.sleep(1000);
        var values = ss.getRange('Monster!A2:C2').getValues()[0];
      }
      while( values.every(value => value === '') || Date.now() - start < limit);
    
      // Copy / paste the formula results
      ss.getRange('Monster!A1:C').copyTo(ss.getRange('Page 2!A1:A'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
    
      // Clear A1, B1, C1
      ss.getRange('Monster!A1:C1').clear({contentsOnly: true, skipFilteredRows: true});
    }
    

    【讨论】:

      【解决方案2】:

      Lockservice 锁定脚本执行 - 它不会锁定对电子表格的访问 - 无论是用户还是公式

      如果您想要使用同步代码,以便在前一个请求完成之前不会执行请求(例如设置公式或复制值) - 您可以使用 SpreadsheetApp.flush() 和 Utilities.sleep()。

      • 前者等到最后一次调用 SpreadsheetApp 完成

      • 后者给脚本一些额外的时间 - 等待表格公式正确更新可能很有用。

      • 您需要在代码中多次使用这些请求 - 只要适用。

      示例:

      function myFunction() {
        var ss = SpreadsheetApp.getActive();
        ss.getRange('Monster!A1').setFormula('=IMPORTXML(Gerais!R1,"//*[@class=\'header-label\']"');
        //modify the watiting time depending on how long you expect the formula to take to importa data
        Utilities.sleep(1000);
        ss.getRange('Monster!A1:A').copyTo(ss.getRange('Page 2!A1:A'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
        SpreadsheetApp.flush();
        ss.getRange('Monster!A1').clear({contentsOnly: true, skipFilteredRows: true});
        SpreadsheetApp.flush();
        ss.getRange('Monster!B1').setFormula('=IMPORTXML(Gerais!R2,"//*[@class=\'header-label\']"');
        Utilities.sleep(1000);
        ss.getRange('Monster!B1:B').copyTo(ss.getRange('Page 2!B1:B'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
        SpreadsheetApp.flush();
        ss.getRange('Monster!B1').clear({contentsOnly: true, skipFilteredRows: true});
        SpreadsheetApp.flush();
        ss.getRange('Monster!C1').setFormula('=IMPORTXML(Gerais!R3,"//*[@class=\'header-label\']"');
        Utilities.sleep(1000);
        ss.getRange('Monster!C1:C').copyTo(ss.getRange('Page 2!C1:C'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
        SpreadsheetApp.flush();
        ss.getRange('Monster!C1').clear({contentsOnly: true, skipFilteredRows: true});
      // not necessary to flush at the end of the script
      }
      

      【讨论】:

      • 非常感谢您的回答,因为您告诉我的内容,所以如果 IMPORTXML 已返回结果,真的没有选项可以忠实地继续执行脚本,我们最多只能尝试想象一下导入和创建暂停所需的最长时间,我这样想对吗?
      • AFAIK 就是这样。
      猜你喜欢
      • 1970-01-01
      • 2020-07-20
      • 2020-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多