通过 Google 表格解析时出现“JavaScript 运行时意外退出”错误

Posted

技术标签:

【中文标题】通过 Google 表格解析时出现“JavaScript 运行时意外退出”错误【英文标题】:"The JavaScript runtime exited unexpectedly" error when parsing through Google Sheets 【发布时间】:2021-08-23 14:20:46 【问题描述】:

我有一个函数getFnF(),它遍历 Google Drive 文件夹及其所有子文件夹。当getFnF() 遇到 Google 表格文件时,我让脚本解析该 Google 表格文件并使用我的函数getLinksFromSheet() 提取它找到的任何 URL 链接。这两个函数都可以工作,但是在遍历 Drive 文件夹并在遇到的 Google 表格文件上调用 getLinksFromSheet() 大约 10 分钟后,我收到了 The javascript runtime exited unexpectedly. 错误。有没有人知道什么会导致这个错误? Google Drive 文件夹非常大(子文件夹中总共有约 500 个文件,其中约 75 个是 Google 表格)。代码如下:

function getFnF(folder) 
  var folder= folder || DriveApp.getFolderById("0AFZNRhJpE8LKUk9PVA"); //hard goded DEP-Gotham folder
  
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName('Sheet1');
  var files=folder.getFiles();
  
  while(files.hasNext()) 
    var file=files.next();
    var firg=sh.getRange(sh.getLastRow() + 1,level + 1);
    firg.setValue(Utilities.formatString('File: %s', file.getName()));
    Logger.log(file.getName())
    //if (file.getMimeType() == 'application/vnd.google-apps.document') getAllLinks(file.getId(), false);;
    //if (file.getMimeType() == 'application/vnd.google-apps.presentation') getLinksFromSlides(file.getId());;
    if (file.getMimeType() == 'application/vnd.google-apps.spreadsheet') getLinksFromSheet(file.getId());;
  

  var subfolders=folder.getFolders() 
  while(subfolders.hasNext()) 
    var subfolder=subfolders.next();
    var forg=sh.getRange(sh.getLastRow() + 1,level + 1);
    forg.setValue(Utilities.formatString('Fldr: %s', subfolder.getName()));
    level++;
    getFnF(subfolder);
  

  level--;


function getLinksFromSheet(sheetId)
 var ss = SpreadsheetApp.openById(sheetId); 
 var sheets = ss.getSheets();
 var parentDocName = ss.getName();

 var destSs=SpreadsheetApp.getActive();
 var destSh=destSs.getSheetByName('Extracted Links');
 
 sheets.forEach(sheet => 
  var rangeData = sheet.getDataRange();
  var lastColumn = rangeData.getLastColumn();
  var lastRow = rangeData.getLastRow();
  var searchRange = sheet.getRange(1,1, lastRow, lastColumn);
  //var rangeValues = searchRange.getValues();
  var rangeValues = searchRange.getRichTextValues();


    for (var i = 0; i < lastRow; i++)
      for (var j = 0; j < lastColumn; j++)
       
        const runs = rangeValues[i][j].getRuns();

        for (const v of runs) 
           var nextLink = v.getLinkUrl();
           if (nextLink != null) 
           var row = destSh.getLastRow() + 1;
           var r1=destSh.getRange(row, 1);
           r1.setValue(parentDocName);
           var r2=destSh.getRange(row, 2);
           r2.setValue(nextLink);
           ;
      
    
  
);

【问题讨论】:

可能只是没时间了吧? developers.google.com/apps-script/guides/services/… @MattKing 我再次运行脚本,这次我在 4 分钟后得到了错误。可能有不同的原因吗?另外,有什么办法可以更新脚本以使其运行得更快? @GabrielTero,你能在下面尝试我的修改吗?它应该能够为您节省一些时间并使您的脚本更快。 【参考方案1】:

问题很可能源于超出运行时执行的限制。

您可以使用getFilesByType 进一步精简列表并节省时间。也确实在您的代码中进行了一些修改,但应该能够做同样的事情。它们上面应该有 cmets。请检查。

用法:

function getFnF(folder) 
  var folder = folder || DriveApp.getFolderById("0AFZNRhJpE8LKUk9PVA"); //hard goded DEP-Gotham folder

  var ss = SpreadsheetApp.getActive();
  var sh = ss.getSheetByName('Sheet1');
  // limit files to only google sheets
  var files = folder.getFilesByType(MimeType.GOOGLE_SHEETS);
  
  // assign getLastRow to lessen method calls
  var lastRow = sh.getLastRow();
  // initialize level value
  var level = 1;

  while (files.hasNext()) 
    var file = files.next();
    // I can use appendRow here, but I did't since column has a variable
    // and you might change it. Feel free to update if necessary
    var firg = sh.getRange(lastRow + 1, level + 1);
    firg.setValue(Utilities.formatString('File: %s', file.getName()));
    getLinksFromSheet(file.getId()); 
    // iterate lastRow
    lastRow++;
  

  var subfolders = folder.getFolders()
  while (subfolders.hasNext()) 
    var subfolder = subfolders.next();
    // I can use appendRow here, but I did't since column has a variable
    // and you might change it. Feel free to update if necessary
    var forg = sh.getRange(lastRow + 1, level + 1);
    forg.setValue(Utilities.formatString('Fldr: %s', subfolder.getName()));
    level++;
    getFnF(subfolder);
    // iterate lastRow
    lastRow++;
  
  // not sure what this does but you can freely remove this if not being used
  level--;


function getLinksFromSheet(sheetId) 
  var ss = SpreadsheetApp.openById(sheetId);
  var sheets = ss.getSheets();
  var parentDocName = ss.getName();

  var destSs = SpreadsheetApp.getActive();
  var destSh = destSs.getSheetByName('Extracted Links');

  sheets.forEach(sheet => 
    // getDataRange already gets all the data
    var rangeData = sheet.getDataRange();
    // Flatten 2d array
    var rangeValues = rangeData.getRichTextValues().flat();
    
    rangeValues.forEach(v => 
      var link = v.getLinkUrl();
      if(link)
        // Use appendRow instead. Adjust array if needed to be in a different column.
        destSh.appendRow([parentDocName, link]);
    );
  );

运行时差:

6 秒的运行是上面优化的,而 7 秒的运行是你的代码。

测试条件:

父文件夹中有两个图纸文件,1 个子文件夹中有一个图纸文件: 每个电子表格有 2 个工作表,每个工作表有 1 个链接。 父文件夹有一个非工作表文件。

注意:

考虑到少量文件的显着运行时差异,这肯定会对大量文件产生更大的影响。 如果您想包含其他类型的文件,那么您需要创建一个单独的循环来处理每个文件类型,如果您对每个文件类型有不同类型的进程。 您也可以将 2 个getFilesByType 输出连接到 1 个数组中,但从不同文件类型获取链接可能会有所不同,因此单独的循环会更安全。

【讨论】:

【参考方案2】:

为了解决您遇到的时间问题,我建议使用一个脚本来编写所有电子表格 ID,然后使用另一个脚本来处理它们(运行 getLinksFromSheet())一次一行,然后标记每个行,这样你就可以重新运行它,直到你完成。

Getrichtextvalue > getlinkURL 只是缓慢的wwwwwwwww,您无法绕过它。

【讨论】:

以上是关于通过 Google 表格解析时出现“JavaScript 运行时意外退出”错误的主要内容,如果未能解决你的问题,请参考以下文章

重新加载 UITableview 时出现问题..!

与 Google Drive 集成时出现凭据错误

从谷歌搜索建议解析xml结果时出现异常

解析“2020-03-30T07:37:02.282+01:00”类型的日期时出现日期格式化问题,我必须在今天上午 12:30 格式化表格

使用 ISO-8859-1 编码解析 DataMatrix 时出现未知编码错误

在 iOS 项目(在 Swift 中)设置 Google Analytics 时出现“保护体可能无法通过”错误 [重复]