加速 Google App 脚本/Javascript 和递归

2024-03-23

我正在 Google App Script 中为 Google Sheet 编写一组脚本。我创建了一个用户界面来为 Google Sheet 提供网页体验,充当论坛。我以递归模式将讨论存储在电子表格中,如下所示:

  ID    |    Parent_ID  |   Title      |      Note                | Forum_ID   | Is_Active  

1       |   0           |  Some Title  |       Some Discussion    | 100        | True

2       |   0           |  Some Title  |       Some Discussion    | 100        | True

3       |   2           |  Some Title  |       Some Discussion    | 100        | True

4       |   3           |  Some Title  |       Some Discussion    | 100        | True

5       |   2           |  Some Title  |       Some Discussion    | 100        | True

因此,嵌套的层数可以是不确定的。当页面加载时,它调用一个脚本,传入一个ID,该ID始终是上层节点的根ID(其中Parent_ID始终为0)。然后我返回一个节点,其中包含所有嵌套的子节点。然后,我需要使用嵌套组中每条记录的 ID 来执行一些计算。我的代码可以工作,但可能非常慢。迭代超过 20 条记录可能需要 15 秒以上的时间。任何人都可以提供有关如何加快速度并使代码更高效的反馈吗?这是我的代码:

function GetMessageBoardChildren(message_id) {
    console.time('Gettingcomments') //this block of code can take around 2-3 seconds to run through (where the number of records is about 50)
    var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
    var sheet = ss.getSheetByName(MESSAGE_BOARD);
    var rows = sheet.getDataRange().getValues();               
    var newArray = [];
    var CommentsArray = [];   
    for (var i = 1; i < rows.length; i++) {
        var row = rows[i];     
        if (row[5] == 1) {        
             CommentsArray.push({
                post_id: row[0].toString(),
                parent_id: row[1].toString(),
                forum_id: row[2].toString(),
                title: htmlEscape(row[3].toString()),
                message: htmlEscape(row[4].toString()),
                is_active: row[5].toString(),
                date_created: ConvertUnixTimeStampToDateTime(row[6].toString()),
                created_by_id: row[8].toString()      
            })
        }    
    }   
    console.timeEnd('Gettingcomments') 
   
    console.time('BuildgingTree')// this is fast.  couple of miliseconds
    tree = nest( CommentsArray );  
    for(var j = 0; j<tree.length; j++){ 
      if(tree[j].post_id == message_id){
         newArray.push(tree[j])
      }
    }
   console.timeEnd('BuildgingTree')
   
   console.time('recursing') //this can take 11-15 seconds to complete
   var t = recursePosts(newArray);
   console.timeEnd('recursing')
   return t;  

}

function recursePosts(posts){      
  for(var i=0;i<posts.length;i++){
    if(posts[i].children){
      recursePosts(posts[i].children)
     } 
     console.time('GettingVotes')
     var voteCount = GetVotesByCommentId(posts[i].post_id); 
     posts[i].number_up_posts = voteCount.upVote,
     posts[i].number_down_posts = voteCount.downVote
     console.timeEnd('GettingVotes')
     console.time('GettingUsername')
     posts[i].created_by = GetUserNameByUserId( posts[i].created_by_id);
     console.timeEnd('GettingUsername')
     posts[i].created_by_id="";     
  }
  return posts;
}

const nest = (items, id = '0', link = 'parent_id') =>items
    .filter(item => (item[link] === id )  )
    .map(item => ({ ...item,children: nest(items, item.post_id) }));

function ConvertUnixTimeStampToDateTime(unix_timestamp) {
    var a = new Date(unix_timestamp * 1000);
    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    var year = a.getFullYear();
    var month = months[a.getMonth()];
    var date = a.getDate();
    var hour = a.getHours();
    var min = a.getMinutes();
    var sec = a.getSeconds();
    var time = a.getMonth() + "/" + date + "/" + year + " " + hour + ":" + min + ":" + sec;   
    return time;

}
function htmlEscape(str){
//prevent injection
    return str.replace(/<[^>]+>/g, "")
}
function GetUserNameByUserId(ID){
   var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
   var sheet = ss.getSheetByName(USERS);
   var rows = sheet.getDataRange().getValues();
   var userName = "";
   
   for (var i = 1; i < rows.length; i++) {
     var row = rows[i];
     if(row[0] === ID){
       userName = row[3];
       break;
     }
   }
   if(userName == ""){
     userName = "Admin"
   }
   return userName;    
}

function GetVotesByCommentId(comment_id) {
    var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
    var sheet = ss.getSheetByName(COMMENT_VOTES);
    var rows = sheet.getDataRange().getValues();
    var countUp = 0;
    var countDown = 0;

    for (var i = 0; i < rows.length; i++) {
      var row = rows[i];
        if (row[1] === comment_id && row[2] === 1) {
            countUp++;
        }else if (row[1] === comment_id && row[2] === -1){
          countDown++;
        }        
    }
    return {upVote:countUp, downVote:countDown};
}

功能recursePosts正在重新加载并重新初始化多个变量,例如ss, sheet and rows在内部函数中多次。您应该使这些变量在父作用域中保持不变,并仅调用这些方法一次

const config = {
  ss: null,
  mb_sheet: null,
  users_sheet: null,
  comments_sheet: null,
  mb_rows: null,
  users_rows: null,
  comments_rows: null,
};

function initAll_() {
  config.ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
  [config.mb_sheet, config.users_sheet, config.comments_sheet] = [
    MESSAGE_BOARD,
    USERS,
    COMMENT_VOTES,
  ].map(name => config.ss.getSheetByName(name));
  [config.mb_rows, config.users_rows, config.comments_rows] = [
    config.mb_sheet,
    config.users_sheet,
    config.comments_sheet,
  ].map(sheet => sheet.getDataRange().getValues());
}


function GetMessageBoardChildren(message_id) {
  /*Initialize everything once and only once*/initAll_();
  console.time('Gettingcomments'); 
  //Removed var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
  // var sheet = ss.getSheetByName(MESSAGE_BOARD);
  var rows = /*Modified*/ config.mb_rows;
  /*stuff*/
}

function GetUserNameByUserId(ID) {
  // var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
  // var sheet = ss.getSheetByName(USERS);
  var rows = config.users_rows
  /*stuff*/
}

function GetVotesByCommentId(comment_id) {
  // var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
  // var sheet = ss.getSheetByName(COMMENT_VOTES);
  var rows = config.comments_rows;
  /*stuff*/
}

如果您想要变量的模块化加载,您可以使用这里描述了延迟加载技术 https://stackoverflow.com/questions/65150194/how-to-use-global-variables-while-avoiding-permissio

/**
 * A sheet configuration object containing class sheet and
 *   it's full datarange values
 * @typedef {Object} SheetConfig
 * @property {GoogleAppsScript.Spreadsheet.Sheet} sheet
 * @property {Object[][]} values
 */

/**
 * Global configuration object
 * @type {{
 * ss:GoogleAppsScript.Spreadsheet.Spreadsheet,
 * [x:string]:SheetConfig|GoogleAppsScript.Spreadsheet.Spreadsheet}}
 */
const config = {
  get ss() {
    delete this.ss;
    return (this.ss = SpreadsheetApp.getActive());
  },
};
(function addSheetGettersToConfig_() {
  /*Add 3 {SheetConfig}  to config object*/
  [MESSAGE_BOARD,USERS,COMMENT_VOTES,].forEach(name =>
    Object.defineProperty(config, name, {
      enumerable: true,
      configurable: true,
      get: function() {
        delete this[name];
        return (this[name] = {
          sheet: this.ss.getSheetByName(name),
          get values() {
            delete this.values;
            return (this.values = this.sheet.getDataRange().getValues());
          },
        });
      },
    })
  );
})();

console.log('config before');
console.log(config);

function test_lazyLoading() {
  console.log(config[MESSAGE_BOARD].values);
  console.log('config after');
  console.log(config);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

加速 Google App 脚本/Javascript 和递归 的相关文章

随机推荐

  • ItemsControl 和 Canvas 中的多个数据模板

    我试图在画布上显示一些框 我自己的 userControl 在其自己的名为 singleNodeControl 的 xaml 文件中定义 并用线连接它们 普通 xaml Line 元素绑定到 LineToParent 类 这两项都存储在 v
  • 使用 PHPExcel 读取电子表格

    我正在尝试上传电子表格并使用 PHPExcel 将其读入 MySQL 数据库 对于 xlsx 文件 它工作正常 但每当我尝试上传 ods 文件时 它都会抛出错误 PHP Fatal error Call to a member functi
  • 如何使用 C# 更新数据透视表数据源?

    我想知道如何更新现有的数据透视表数据源 我在用Microsoft Office Interop Excel并针对使用 Excel 2010 的用户 我目前能够刷新工作正常的数据透视表 但是当添加更多行时 我希望将这些行包含在数据透视表数据源
  • WPF:我可以强制窗口重新评估其所有绑定和验证吗?

    我可以强制窗口重新评估其所有绑定和验证吗 由于某种原因 它似乎在一种奇怪的情况下忽略了 INotifyPropertyChanged PropertyChanged 我正在寻找一种解决方法 直到找到真正的原因 不幸的是 我知道没有办法强制窗
  • 如何在Linux中安装chrome(无头)

    我有一个运行 linux redhad 的 AWS EC2 有没有办法在上面安装最新的 Chrome v59 以便我可以像 PhantomJS 一样以无头模式运行它 我在 google 上能找到的所有资源都是关于如何在有 UI 的 ubun
  • 无法转换“UICollectionViewCell”类型的值

    我在 Storyboard 中使用自定义 CollectionViewCell 当我启动应用程序时 我收到以下消息 无法将 UICollectionViewCell 类型的值转换为 TestProject CollectionViewCel
  • 框架在不同时间绘画? [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我的游戏中有一个非常烦人的错误 帧的底部似乎比帧的顶部渲染得更早 我不确定为什么会发生这种情况 我正在使用 JPanel
  • Python 的 bool 值是按值传递的吗?

    我发送了对 bool 对象的引用 并在方法中修改了它 方法执行完毕后 方法外的bool值没有变化 这让我相信 Python 的 bool 是按值传递的 真的吗 还有哪些其他 Python 类型有这样的行为 Python 变量不是 C 意义上
  • Pip 安装日志在哪里?

    为什么 pip 不记录何时安装了哪个版本的库 如果您将库更新为损坏的版本怎么办 你怎么知道哪个版本没有被破坏 那些对此投赞成票的人 你能告诉我你为什么这样做吗 运行 pip 时 您可以指定日志文件 这样您就可以在将来跟踪安装日志 pip i
  • n最大和n最小;堆Python

    这是出于对 python 中 heapq py 模块的 nsmallest 和 nlargest 方法的好奇 我正在读它here https docs python org 2 library heapq html 在文档中 文档没有说明它
  • 按类型组合连续日期时间间隔

    假设我们有这样一个表 declare periods table s date e date t tinyint 日期间隔无间隙 按开始日期排序 insert into periods values 2013 01 01 2013 01 0
  • 如何在 Typescript 中启用 NodeJS 和 ExpressJs

    我希望找到一个适用于 Node 和 Express 的 d ts 文件 这将在打字稿中启用 Intellisense 到目前为止 我已经尝试使用此处提供的 Node d ts 文件 https github com borisyankov
  • Maven 快照到底是什么以及我们为什么需要它?

    我对 Maven 快照的含义以及我们为什么要构建一个有点困惑 Maven 中的快照版本是尚未发布的版本 这个想法是before a 1 0发布 或任何其他发布 完成后 存在1 0 SNAPSHOT 那个版本是什么可能会成为 1 0 基本上就
  • 一台服务器向 Android 和 iOS 设备发送推送通知

    我们的组织有一个 Android 应用程序和一个 iOS 应用程序 我们希望开始向这些应用程序推送通知 安卓有GCM 苹果有APNS 但我们想要创建一个可以在 Android 和 iOS 上运行的 API 设置服务器的最简单方法是什么 以便
  • 反应式香蕉中的动态事件切换导致严重泄漏

    我不确定这种行为是预期的 即我误用了 Reactive Banana Switch 还是错误 假设我有两个类似类型的输入行为 并且我想根据事件在它们之间进行切换 我写了这个函数 switchBehaviors Behavior t a Be
  • 从 WCF 服务抛出FaultException 会导致“此故障的创建者未指定原因”。

    当投掷一个FaultException
  • 从 openapi-generator 生成提示登录时添加行 import openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID"

    我正在使用 openapi 生成器来生成我的其余 api 客户端 它生成行 openapiclient github com GIT USER ID GIT REPO ID 在我的进口中 但我一生都无法理解为什么 运行一个go mod ve
  • CONN_MAX_AGE 在 Django 中如何工作

    有人可以 ELI5 CONN MAX AGE 做什么吗 我认为它是这样工作的 1 请求 1 进入 打开到数据库的连接 1 2 请求 1 使用连接 1 来做一些工作 3 请求 1 完成 由于 CONN MAX AGE 不为零 并且尚未达到期限
  • Typescript 类型的递归子集

    在 Typescript 中是否可以创建与此类似的类型子集 type Schema user name string age number profile isCool boolean const wantedSubset user nam
  • 加速 Google App 脚本/Javascript 和递归

    我正在 Google App Script 中为 Google Sheet 编写一组脚本 我创建了一个用户界面来为 Google Sheet 提供网页体验 充当论坛 我以递归模式将讨论存储在电子表格中 如下所示 ID Parent ID T