谷歌脚本运行速度太慢

时间:2016-08-30 17:39:56

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

我目前正在编写一个谷歌脚本,但遗憾的是运行速度太慢。 (超过6分钟的限制)。该脚本打开一个文档,替换两个字符串(在google工作表中设置),将其另存为PDF。没什么好看的。

我有大约200个这样的文档来运行这个脚本,但在6分钟的限制内,它只能通过6个。谷歌脚本是这么慢,还是我不小心制作了效率最低的谷歌脚本?

function createAllPDF() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var range = SpreadsheetApp.getActiveSheet().getActiveRange()
  var numRows = SpreadsheetApp.getActiveSpreadsheet().getLastRow() - 1;
  for(var i = 9; i <= numRows; i++) {
    var thisRange = sheet.getRange("A" + n + ":C" + n);
    var fond = thisRange.getCell(1, 1).getValue();
    var adresse = thisRange.getCell(1, 3).getValue();
    thisRange.setBackground('#cfe2f3');
    genDoc(fond, adresse);
  }
}
//// CREATE PDF ////////////////// FUNCTION FOR GENERATING THE PDF  /////////////////////////////////
function genDoc(fond, adresse) {
  // Finds the template and duplicate it into a new file.
  var template = ("xxxxxxxxxxxx");
  var docId = DriveApp.getFileById(template).makeCopy().getId();
  // Opens the newly created Document for editing
  var doc = DocumentApp.openById(docId);
  var body = doc.getActiveSection();
  // Renames the newly generated document
  var newName = doc.setName(fond);
  // Replaces each with the parsed variables.
  body.replaceText("%FOND%", fond);
  body.replaceText("%ADRESSE%", adresse);
  doc.saveAndClose();
  //Adds the PDF ID to the invoice_input sheet
  var conv = DriveApp.getFileById(docId);
  var pdf = conv.getAs("application/pdf");
  var fileId = DriveApp.createFile(pdf).getId();
  // Gets the PDF file by ID
  var thisPDF = DriveApp.getFileById(fileId);
  // The ID of the folder I'd like to put the PDF into.
  var folderId = "xxxxxxxxxxx";
  // Gets the folder by ID
  var targetFolder = DriveApp.getFolderById(folderId);
  // Adds the PDF to the Folder
  targetFolder.addFile(thisPDF);
  // Removes the PDF from the root.
  var root = DriveApp.getRootFolder().removeFile(thisPDF);
  // Deletes the duplicated document
  DriveApp.getFileById(docId).setTrashed(true)
  return fileId;
}

任何关于如何优化的指针都将非常受欢迎。我对谷歌脚本和编程很新,所以没什么大不了的,呵呵。 如果我正在使用此板,请道歉。请让我知道,我会纠正。

2 个答案:

答案 0 :(得分:1)

我立即注意到你有一个未定义的变量n。它在行:

var thisRange = sheet.getRange("A" + n + ":C" + n);

这应该使代码完全无法使用。将这些变量更改为i后,我能够成功运行代码整整6分钟。在那段时间里,它能够循环约41.5次。它为第9-53行创建了文件,但在能够将最后一个文件添加到正确的文件夹之前停止了。

查看执行记录,您最长的操作是创建,移动和删除文件的几次调用。

您还定义了range,然后从不使用此变量,这使得它变得不必要。

我在自己多次使用的结构和方法中重写了代码。我能够完全处理第9-59行。这种方法能够将其扩展6行。我建议添加一个超时触发器,每隔5min55秒停止一次该功能,然后在5秒后重新启动它。有关javascript时间的指南可以找到here。我也使用不同的匹配方法;使用RegEx。 RegEx有广泛的指南以及如何最大限度地缩短处理时间。我对这个领域的熟练程度不高。

function PDFCreator() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Test Sheet");
  var lastRow = sheet.getLastRow();
  var checkRange = sheet.getRange(9, 1, (lastRow - 8), 3);
  var check = checkRange.getBackgrounds();
  var lightBlue = "#cfe2f3";
  var template = DriveApp.getFileById("1RslWGntAwfLTSytOv_IoOv2_iBhSmsK0ZtEVWaq3ezM");
  var folder = DriveApp.getFolderById("0BwZ6LWJudkOHaTFiQjd5cFA5OG8");
  for (i = 0; i < check.length; i++) {
    if (check[i] == lightBlue) {
      continue;
    } else {
      var dataRow = sheet.getRange((i + 9), 1, 1, 3);
      var fond = sheet.getRange((i + 9), 1, 1, 1).getValue();
      var adresse = sheet.getRange((i + 9), 3, 1, 1).getValue();
      var docName = fond + ".pdf";
      var docCopy = template.makeCopy(docName, folder);
      var docId = docCopy.getId();
      var docToEdit = DocumentApp.openById(docId);
      var docBody = docToEdit.getBody();
      docBody.replaceText(/\%{1}[F][O][N][D]\%{1}/g, fond);
      docBody.replaceText(/\%{1}[A][D][R][E][S][S][E]\%{1}/g, adresse);
      docToEdit.saveAndClose();
      var fileToPDF = DriveApp.getFileById(docId);
      var pdfBlob = fileToPDF.getAs(MimeType.PDF);
      var pdfRoot = DriveApp.createFile(pdfBlob).setName(docName);
      var pdf = pdfRoot.makeCopy(folder);
      pdfRoot.setTrashed(true);
      fileToPDF.setTrashed(true);
      dataRow.setBackground(lightBlue);
    }
  }
}

你会注意到我嵌套了main函数中的for()if()。这样,您不会反复在函数之间来回传递信息。通常,您可以越多地定义之外的循环,您将需要进行的调用越少。我可以在for循环之外设置更多变量,以进一步扩展它的运行。

基本上,这是一个漫长的过程,并且它无法在6分钟内运行200次。你可以将这个行扩展到55/60行,效率很高,但此时你只需要再次运行它。

答案 1 :(得分:0)

(注意:尚未对此进行测试,但应该让您入门)

一些想法:

  1. 将“getRange”命令移出for循环。
  2. 读取for循环之外的模板,targetFolder和rootFolder,并将它们作为参数传递给genDoc。
  3. 尽可能重复使用“sheet”和“conv”。
  4. 立即写下所有bgColors,而不是单独写。
  5. 不要退货。
  6. 这样的事情:

    function createAllPDF() {
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
      var numRows = sheet.getLastRow() - 1;
      var range = sheet.getActiveRange();
      var values = range.getValues();
      var templateId = ("xxxxxxxxxxxx");
      var template = DriveApp.getFileById(templateId);
      // The ID of the folder I'd like to put the PDF into.
      var folderId = "xxxxxxxxxxx";
      // Gets the folder by ID
      var targetFolder = DriveApp.getFolderById(folderId);
      var rootFolder = DriveApp.getRootFolder();
      for(var i = 9; i <= numRows; i++) {
        var fond = values[i][1]; // TODO: check syntax.
        var adresse = values[i][3];
        genDoc(fond, adresse, template, targetFolder, rootFolder);
      }
      range.setBackground('#cfe2f3'); // TODO: only first 3 columns
    }
    //// CREATE PDF ////////////////// FUNCTION FOR GENERATING THE PDF  /////////////////////////////////
    function genDoc(fond, adresse, template, targetFolder, rootFolder) {
      // Finds the template and duplicate it into a new file.
      var conv = template.makeCopy();
      var docId = conv.getId();
      // Opens the newly created Document for editing
      var doc = DocumentApp.openById(docId);
      var body = doc.getActiveSection();
      // Renames the newly generated document
      var newName = doc.setName(fond);
      // Replaces each with the parsed variables.
      body.replaceText("%FOND%", fond);
      body.replaceText("%ADRESSE%", adresse);
      doc.saveAndClose();
      //Adds the PDF ID to the invoice_input sheet
      var pdf = conv.getAs("application/pdf");
      var fileId = DriveApp.createFile(pdf).getId();
      // Gets the PDF file by ID
      var thisPDF = DriveApp.getFileById(fileId);
      // Adds the PDF to the Folder
      targetFolder.addFile(thisPDF);
      // Removes the PDF from the root.
      rootFolder.removeFile(thisPDF);
      // Deletes the duplicated document
      conv.setTrashed(true);
    }